当数据类型为TIMESTAMP和TIMEZONE

时间:2018-08-06 17:49:35

标签: sql oracle

因此,如果符合条件,我有一些逻辑将尝试获取与前一个小时相关的值(VALUE)。 HOUR列是带有TIME ZONE的TIMESTAMP列。我以为我可以运行以下查询,但是出现 ORA-00932数据类型不一致:预期的TIMESTAMP WITH TIME ZONE出现NUMBER 错误。我必须在“带时区的时间戳”值中添加某种转换功能吗?

以下是我的查询代码:

SELECT MAX(VALUE)
  FROM VALUE V
 WHERE CODE = 'HI'
   AND HR = '15-JAN-17 05.00.00.000000000 AM' - (1/24);

谢谢。

2 个答案:

答案 0 :(得分:2)

使用TO_TIMESTAMP'15-JAN-17 05.00.00.000000000 AM'设置为日期时间,然后减去一小时。

SELECT MAX(VALUE)
  FROM VALUE V
 WHERE CODE = 'HI'
   AND HR =  TO_TIMESTAMP('15-JAN-17 05.00.00.000000000 AM','DD-MON-RR HH.MI.SS.FF AM') - (1/24);

答案 1 :(得分:2)

'15-JAN-17 05.00.00.000000000 AM'是字符串,而不是时间戳。您可以按照@ D-Shih的建议将其转换为时间戳(无时区),但应指定格式掩码和日期语言,而不要依赖NLS设置:

AND HR = to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
 'NLS_DATE_LANGUAGE=ENGLISH') - (1/24);

或者它是一个固定值(大概不是,或者您可以更改该文字):

AND HR = timestamp '2017-01-15 05:00:00' - (1/24);

从时间戳中减去几天会得到一个日期结果,所以您也许真的想做:

AND HR = timestamp '2017-01-15 05:00:00' - interval '1' hour;

现在它保留为时间戳,但是您没有时区信息。如果您知道时区,则可以将其包含在字符串文字和格式掩码中,或者包含在时间戳文字中,例如:

AND HR = timestamp '2017-01-15 05:00:00 America/Los_Angeles' - (1/24);

或者从您的原始字符串开始,如果您只需要使用它,则可以使用from_tz()

AND HR = from_tz(to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
  'NLS_DATE_LANGUAGE=ENGLISH'), 'America/Los_Angeles') - interval '1' hour;

最后进行间隔减法意味着它可以正确处理DST。

从您的字符串值开始的各种转换的演示:

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF1';
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF1 TZR TZD';

select
  to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
    'NLS_DATE_LANGUAGE=ENGLISH') as a_timestamp,
  to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
    'NLS_DATE_LANGUAGE=ENGLISH') - (1/24) as b_date,
  to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
    'NLS_DATE_LANGUAGE=ENGLISH') - interval '1' hour as c_timestamp,
  from_tz(to_timestamp('15-JAN-17 05.00.00.000000000 AM', 'DD-MON-RR HH.MI.SS.FF AM',
  'NLS_DATE_LANGUAGE=ENGLISH'), 'America/Los_Angeles') - interval '1' hour as d_timestamp_tz
from dual;

A_TIMESTAMP           B_DATE              C_TIMESTAMP           D_TIMESTAMP_TZ                               
--------------------- ------------------- --------------------- ---------------------------------------------
2017-01-15 05:00:00.0 2017-01-15 04:00:00 2017-01-15 04:00:00.0 2017-01-15 04:00:00.0 AMERICA/LOS_ANGELES PST