bonkerssdn 2015-05-13
早上收到开发人员发来的邮件,说在一个测试环境中SQL执行报错,但相同的SQL在另一个测试环境中却执行经常,叫我帮忙分析一下原因。报错的SQL为:
SQL> select to_date(substr(cvalidate, 6, 10), 'MM-DD') from lcpol where polno='210010000123931';
select to_date(substr(cvalidate, 6, 10), 'MM-DD') from lcpol where polno='210010000123931';
*
ERROR at line 1:
ORA-01839: date not valid for month specified
一看错误信息是ORA-01839: date not valid for month specified。首先想到可能是数据有问题导致在使用TO_DATE报错。不管怎样先去求证下是不是真的存在该错误。首先连接上说执行报错的库,执行SQL,果然如开发人员所说报错。接着连接上说执行正常的库,执行SQL,果然Oracle很友好的返回了结果。既然错误事实存在,那就要去找出导致错误的原因了。
按照对错误的第一反应,先去比对两边的数据是否一样。比对结果有点令人失望,两边的数据完全一模一样。难道是SQL本身存在问题?仔细分析下SQL,应该没错啊,虽然使用'MM-DD'格式化的写法不怎么好,但也应该不至于导致执行错误啊,况且在另外的库上是执行正确的。那问题到底处在哪呢?难道是两库的日期参数设置不一样?查看了一下,两个数据库的NLS_CHARACTERSET,
NLS_NCHAR_CHARACTERSET, NLS_DATE_LANGUAGE, NLS_DATE_FORMAT设置也是一样的。好吧,看来问题应该不在数据上。
再回头来看一下,在条件polno='210010000123931'下的cvalidate是个什么值呢?
SQL> select cvalidate from lcpol where polno='210010000123931'; CVALIDATE ---------- 2012-02-29
看来该值确实也比较特殊,4年才会出现一次。但是特殊归特殊,也不应该报错了。想到如果直接用该值会怎样?嗯,那就试试看:
SQL>select to_date(substr('2012-02-29', 6, 10), 'MM-DD') from dual;
ERROR
-----------------------
ERROR at line 1:
ORA-01839: date not valid for month specified
SQL> select to_date(substr('2012-02-29', 6, 10), 'MM-DD') from dual;
TO_DATE(SU
----------
2012-02-29
测试结果还是一样。正一筹莫展之际,突然注意到虽然使用'MM-DD'来格式化日期,但是结果中仍然还有年的信息!想到当前的NLS_DATE_FORMAT为'YYYY-MM-DD',猜测Oracle会使用当前系统的日期来附加年的信息。难道是那台执行错误的库的系统日期不正确,马上查看一下,果然,系统日期是2013年!
$ date
Fri Mar 1 18:45:13 CST 2013
马上联系系统管理小组帮忙修正系统日期。在系统日期修改正确后,SQL执行正常,至此问题解决。