Oracle Timestamp在条件下失败

时间:2017-05-15 05:45:08

标签: sql oracle date timestamp

我有表systemproperties,其中存储了propertyname (varchar)propertyvalue (clob)。根据其中一个属性,

propertyname - RowDate
propertyvalue - 12-MAY-17 04.00.06.883000 PM

另一个表activity,我正在使用timestamp(6)存储日志数据。

查询从activity表中获取日志数据,

select type,startdate from activity where startdate > ?

此处startdatetimestamp(6)类型。我使用的是实际值,结果一无所获。但是,如果我使用如下:

select type,startdate from activity 
where startdate > (select to_char(propertyvalue) 
                   from systemproperties where propertyname='RowDate')

我的行数大于时间。我无法理解这里的区别。任何人都可以在这里指导我。我可以用什么来解决这个问题?

以下是我的NLS设置:

NLS_LANGUAGE    AMERICAN
NLS_TERRITORY   AMERICA
NLS_CURRENCY    $
NLS_ISO_CURRENCY    AMERICA
NLS_NUMERIC_CHARACTERS  .,
NLS_CALENDAR    GREGORIAN
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE   AMERICAN
NLS_SORT            BINARY
NLS_TIME_FORMAT     HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT    DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT  HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY   $
NLS_COMP    BINARY
NLS_LENGTH_SEMANTICS    BYTE
NLS_NCHAR_CONV_EXCP FALSE

提前致谢。

2 个答案:

答案 0 :(得分:1)

您的财产定义如下:

propertyvalue - 12-MAY-17 04.00.06.883000 PM

现在您认为这意味着2017年5月12日,但这不是您所说的。因此,当将字符串12-MAY-17 04.00.06.883000 PM转换为Oracle执行通常所做的日期时,将该世纪默认为00

演示:

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2017-05-14 23:50:09

SQL> select to_date('17-05-14 00:00:00') my_date from dual;

MY_DATE
-------------------
0017-05-14 00:00:00

SQL> 

这就是你得到结果的原因。显然你有很多记录startdate > date '0017-05-12'

  

"我可以使用哪些解决方案?"

最佳解决方案是正确定义日期。这是 2017 ,现在还为时已晚,无法对Y2K错误进行编码。

propertyvalue - 12-MAY-2017 04.00.06.883000 PM

或者,您可以在引用属性时使用显式日期掩码:

startdate > to_date(propertyvalue, 'DD-MON-YY HH.MI.SS.FF6 AM')

在这种情况下,Oracle将用当前世纪20替换掩码的缺失元素。它仍然是一个等待发生的错误,但2000更有可能是正确答案。

  

" startdate是时间戳(6)"

没关系,Oracle在这方面对它们都是一样的:

SQL> alter table t23 add ts timestamp;

Table altered.

SQL> update t23 set ts = systimestamp;

4 rows updated.

SQL> select count(*) from t23 where ts > to_date('17-05-16 00:00:00');

  COUNT(*)
----------
         4

SQL> select count(*) from t23 where ts > to_date('17-05-16 00:00:00', 'yy-mm-dd hh24:mi:ss');

  COUNT(*)
----------
         0

SQL> 

答案 1 :(得分:1)

当您比较startdate > your_property_string时,Oracle将使用适当的TIMESTAMP参数作为格式掩码隐式尝试将属性字符串转换为匹配的数据类型(即NLS_SESSION)。因此WHERE子句将隐式转换为等效于:

WHERE startdate > TO_TIMESTAMP(
                    your_property_string,
                    ( SELECT value
                      FROM   SYS.NLS_SESSION_PARAMETERS
                      WHERE  parameter = 'NLS_TIMESTAMP_FORMAT' )
                  )

因此,Oracle可以为您的属性字符串提供不同的值,具体取决于您NLS_TIMESTAMP_FORMAT的设置值。即如果是YYYY-MON-DD HH12:MI:SS.FF6 AM,那么您的日期将被解析为0015-05-17T16:00:06.883000,如果是DD-MON-YY HH12:MI:SS.FF6 AM,那么它将是2017-05-15T16:00:06.883000

如果要在转换字符串时保持一致,则必须在查询中明确指定格式掩码(以及NLS_DATE_LANGUAGE):

SELECT type,
       startdate
FROM   activity 
WHERE  startdate > TO_TIMESTAMP(
                     ?,
                     'DD-MON-YY HH12.MI.SS.FF6 AM',
                     'NLS_DATE_LANGUAGE=ENGLISH'
                   )