奇怪的Oracle日期行为

时间:2010-01-25 13:42:20

标签: sql oracle

我的一个生产数据库中有一个奇怪的问题。长话短说,简单查询:

select id, trunc(stdate) from table_name where trunc(stdate) = '05-FEB-09';  

没有返回任何行。然而,

select trunc(stdate) from table_name where id = sought_after_id;

返回'05-FEB-09'。只有在我尝试之后:

update table_name set stdate = '05-FEB-09' where id = sought_after_id;

我的原始查询按预期工作:

select id, trunc(stdate) from table_name where trunc(stdate) = '05-FEB-09';
> sought_after_id, '05-FEB-09'

那么,我的标准值发生了什么?

2 个答案:

答案 0 :(得分:5)

你应该总是将日期与日期(苹果到苹果......)进行比较,而不是依赖隐式转换。

由于TRUNC(date)返回日期,您应该将其与日期进行比较:

select id, trunc(stdate) from table_name where trunc(stdate) = DATE '2009-02-05'

select id, trunc(stdate) 
  from table_name 
 where trunc(stdate) = TO_DATE('05-FEB-09', 'DD-MON-RR'))

更新回应Igor的第一条评论:

依赖隐式数据转换会使查询结果依赖于多个会话参数。如果您现在看到前几天的不同结果,则必须修改其中一个参数。您可以通过不依赖隐式转换来使查询“与会话无关”。

值得坚持的是,您的第一个查询取决于客户端会话的参数。如果会话修改其默认日期显示设置 NLS_DATE_FORMAT,您的查询将不会返回相同的结果。

在相关的说明中,DD-MON-RR显示的完全可接受的日期格式,但它不适合在您的代码中使用,因为有关于世纪的含糊不清并且您依赖于NLS_DATE_LANGUAGE参数的几个月。

答案 1 :(得分:4)

可能有两件事。第一个是YY日期掩码可能掩盖了世纪的不同值;如果我们没有使用YYYY指定一个,则默认为当前世纪。第二个是Oracle日期包含一个时间元素。如果我们没有指定时间,则默认为午夜。

SQL> select * from d
  2  /

D1                ID
--------- ----------
19-JAN-10          1
19-JAN-10          3
19-JAN-10          2

SQL> select * from d
  2  where d1 = to_date('19-JAN-10', 'DD-MON-YY')
  3  /

D1                ID
--------- ----------
19-JAN-10          3


SQL> alter session set nls_date_format='DD-MON-YYYY HH24:MI-SS'
  2  /

Session altered.

SQL> select * from d
  2  /

D1                           ID
-------------------- ----------
19-JAN-1910 00:00-00          1
19-JAN-2010 00:00-00          3
19-JAN-2010 12:00-00          2

SQL>

只有一条记录 - #3 - 匹配to_date('19-JAN-10', 'DD-MON-YY')因为#1有不同的世纪而#2有不同的时间。

修改

  

我表格中的所有行都有相同的内容   世纪和00:00-00时间元素。

这是真的现在,但也许只是因为你修复了数据。对于那个特别的约会,肯定有一些不同的东西,否则甲骨文会像其他所有人一样对待它。

通过运行更新,您已删除了差异。事后,我们不可能告诉你数据有什么问题。如果你有一个审计线索,你应该查阅它,因为你知道你的系统的哪个部分插入或更新了那个带有无效日期掩码的记录是有帮助的,所以你可以修复它。