Oracle 根据返回不一致结果的年份选择日期

Posted

技术标签:

【中文标题】Oracle 根据返回不一致结果的年份选择日期【英文标题】:Oracle select dates based on year returning inconsistent results 【发布时间】:2013-05-01 08:38:33 【问题描述】:

我在修改 Oracle 视图时遇到了一个特殊问题。我的想法是我有一个存储所有选举候选人的基表,还有一个选举日期列,告诉我们这个候选人参加了什么选举,就像这样。

NAME       | ELECTION_DATE
---------------------------
John Smith | 01-APR-2011
Alan Cooper| 02-MAY-2013

ELECTION_DATE 列存储为日期。我们使用以下 2011 年的陈述为 2011 年和 2013 年构建了 2 个视图。

where election_date >= to_date(2011,'yyyy') and election_date < to_date(2012,'yyyy')

我们认为这只会收录上面的 John Smith 唱片,但事实并非如此。奇怪的是,当我们为 2013 年视图执行此操作时。

where election_date >= to_date(2013,'YYYY') and election_date < to_date(2014,'YYYY')

它确实获得了 Alan Cooper 的记录。更奇怪的是,如果我们为 2011 年的视图这样做。

where election_date >= to_date(2010,'yyyy') and election_date < to_date(2011,'yyyy')

我们只得到了 John Smith 的唱片,而不是 Alan Cooper 的唱片,这是我们想要的,但不是我们期望的。

然后我们将它们都更改为 between statements,它们的行为完全相同,即 2010 年至 2011 年间获得 John Smith 记录,2011 年至 2012 年间获得任何结果,而 2013 年至 2014 年间获得 Alan Cooper 记录。

在我写这篇文章时,我的同事设法通过使用这个更明确的声明来修复它。

where election_date between  '01-JAN-2011' AND '01-JAN-2012'

但我还是想知道为什么上面的语句仍然如此奇怪?使用 to_date 函数几年来我可能缺少什么?

【问题讨论】:

【参考方案1】:

您是否查看过您的 to_date() 函数实际产生了什么?

select to_date(2011, 'yyyy'), to_date(2012, 'yyyy'), to_date(2013, 'yyyy')
from dual;

TO_DATE(2011,'Y TO_DATE(2012,'Y TO_DATE(2013,'Y
--------------- --------------- ---------------
01-MAY-11       01-MAY-12       01-MAY-13

根据这些日期,您得到的结果是正确的。

如果您不指定月份和日期,则它们默认为当月的第一天,尽管时间默认为午夜。来自documentation for date time literals,这是我能找到的关于这种行为的唯一官方参考:

如果您指定的日期值没有时间组件,则默认 时间是午夜(24 小时制和 12 小时制的 00:00:00 或 12:00:00 时间,分别)。如果您指定没有日期的日期值,则 默认日期是当月的第一天。

如果你要使用

where election_date between  '01-JAN-2011' AND '01-JAN-2012'

...那么您仍然应该使用to_date(),因为您依赖于将来可能会更改的默认日期格式掩码,并且取决于会话。 between 也具有包容性,因此使用您的 2011 年视图将包括 2012 年 1 月 1 日举行的选举,这可能不是您想要的,因此使用 &gt;=&lt; 可能是安全的。或者使用日期文字:

where election_date >= date '2011-01-01' and election_date < date '2012-01-01'

【讨论】:

这一行 - 如果您不指定月份和日期,则它们默认为当月的第一天 - 说明了问题!我假设(错误地)只有一年的 to_date 函数默认为 01/01 而不是 01/current_month。谢谢!【参考方案2】:

尝试将年份提取为 VARCHAR2 并进行比较

select * from table where to_char(ELECTION_DATE, 'yyyy') = `2011` 
or to_char(ELECTION_DATE, 'yyyy') = '2012'

【讨论】:

这会起作用,但会使任何索引都没用——恕我直言,反过来做更有意义。 除非这将是一张表上非常常见的操作,否则需要基于函数的索引。

以上是关于Oracle 根据返回不一致结果的年份选择日期的主要内容,如果未能解决你的问题,请参考以下文章

APICloud AVM 封装日期和时间选择组件

oracle根据出生日期算年龄

oracle根据出生日期算年龄

C#.net 日期控件,如何选择年份,目前只能一个月一个月的选,无法直接选择其它年份

如何根据单独列中的月份和年份参数对 DB2 结果进行排序

android有月份选择器吗?或者怎么让日期选择器的日期不显示,只显示年份和月份