【问题标题】:Oracle DB Ora-01839: date not valid for month specified. 29-02-2016 leap yearOracle DB Ora-01839:指定月份的日期无效。 29-02-2016 闰年
【发布时间】:2016-06-12 05:36:40
【问题描述】:

我们都知道今天是一个特殊的日子。它是闰年的29th of February 2016。

我们从 Oracle DB 中的某些表中收到错误消息。错误是:Oracle ORA-01839: date not valid for month specified。

例如一个简单的选择出错的地方:select * from table where table_date > sysdate -0.1;

对于其他表,此选择没有问题,只是对于某些表。

有没有办法解决这个问题?因为我们今天不能使用很多表。

我们正在使用Oracle 12c。

【问题讨论】:

  • 列table_date的数据类型是什么?
  • @WernfriedDomscheit 这是一个date
  • select table_date from... 是否也会出现该错误 - 也许它是在隐式转换中失败的不同列?是表格还是视图(计算某些东西);还是它有一个虚拟列?会话中出现错误的 NLS_DATE_FORMAT 是什么?您是否在特定客户端中看到了这种情况,并且您可以在 SQL*Plus 中重现吗?
  • 好吧,你浪费了我大部分时间用来解释间隔处理的答案,但很高兴你明白了 *8-) 它是 documented behaviour。

标签: oracle oracle12c leap-year


【解决方案1】:

经过深入研究,很明显为什么我们的某些选择在今天不起作用。该错误是由关键字interval 及其已知问题引起的。 (或者这就是ANSI/ISO spec 所说的应该如何工作,第 205 页底部/第 206 页顶部)

这是来自oracle community blog的引用:

问题:

select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' year as dt from dual;

ORA-01839: date not valid for month specified
01839. 00000 -  "date not valid for month specified"
*Cause:    
*Action:

select to_date('2012-feb-29','yyyy-mon-dd') + interval '2' year as dt from dual;

ORA-01839: date not valid for month specified
01839. 00000 -  "date not valid for month specified"
*Cause:    
*Action:

select to_date('2012-feb-29','yyyy-mon-dd') + interval '3' year as dt from dual;

ORA-01839: date not valid for month specified
01839. 00000 -  "date not valid for month specified"
*Cause:    
*Action:

select to_date('2012-feb-29','yyyy-mon-dd') + interval '4' year as dt from dual;

29-FEB-16 00:00:00


select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' day as dt from dual;

01-MAR-12 00:00:00

select to_date('2012-feb-29','yyyy-mon-dd') + interval '1' month as dt from dual;

29-MAR-12 00:00:00

回答:

这就是 INTERVAL 的工作原理。闰年是最少的 问题;将 1 个月添加到 3 月 31 日会导致相同的错误。如果你 要确保结果是有效的 DATE,然后使用 ADD_MONTHS。 (添加年份没有单独的功能;使用 ADD_MONTH (SYSDATE, 12*n) 得到 n 年后的日期。)


为什么会发生在我们的案例中:

在我们的案例中,出于安全原因,我们对某些表使用了虚拟私有数据库。我们在大多数选择中应用了interval 关键字。

该怎么做:

请改用ADD_MONTHS。

select add_months(to_date('2012-feb-29','yyyy-mon-dd'), 12) as dt from dual;

【讨论】:

  • 请注意,对于夏令时,行为也有所不同。比较 TIMESTAMP '2015-10-25 01:30:00 Europe/Berlin' + INTERVAL '1' MONTH 与 ADD_MONTHS(TIMESTAMP '2015-10-25 01:30:00 Europe/Berlin', 1)
  • 我们错误地编写了类似于以下内容的代码(今天由于 ODP.NET 使用带有DbFunctions.AddYears 的 INTERVAL 导致了这个 Oracle 异常):DataSet.Where(e => e.Date >= DbFunctions.AddYears(DateTime.Now, -1))
  • 谢谢你。我想知道如果你不支持跨月边界和闰年,那么支持日期+间隔有什么意义......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多