当数据类型为 TIMESTAMP 和 TIMEZONE 时如何获取前一小时的值
Posted
技术标签:
【中文标题】当数据类型为 TIMESTAMP 和 TIMEZONE 时如何获取前一小时的值【英文标题】:How to grab the value for the previous hour when the data type is TIMESTAMP with TIMEZONE 【发布时间】:2018-08-06 17:49:35 【问题描述】:因此,如果满足条件,我有一些逻辑将尝试获取与前一小时相关的值 (VALUE)。 HOUR 列是带有 TIME ZONE 列的 TIMESTAMP。我想我可以运行以下查询,但得到 ORA-00932 不一致的数据类型:预期 TIMESTAMP WITH TIME ZONE got NUMBER 错误。我必须将某种转换功能添加到我的“带时区的时间戳”值中吗?
下面是我的查询代码:
SELECT MAX(VALUE)
FROM VALUE V
WHERE CODE = 'HI'
AND HR = '15-JAN-17 05.00.00.000000000 AM' - (1/24);
提前致谢。
【问题讨论】:
【参考方案1】:'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;
最后做间隔减法应该意味着它正确处理了夏令时。
各种转换的演示,从您的字符串值开始:
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
【讨论】:
谢谢!所以问题:如果我要通过复制和粘贴来引用特定的时间戳,如果我要将它添加到我的 WHERE 子句中,我还需要转换它吗? 如果您将其复制并粘贴为字符串,则可以。您可能会摆脱隐式转换,但最好不要依赖它。 (如果该值来自另一个表,那么您应该加入,并将其保留为时间戳而不是字符串。但显然不知道它实际来自哪里。) 感谢@AlexPoole。我需要什么来定义时间戳格式,就好像日期/时间戳可以是 AM 和 FM? 'DD-MON-RR HH.MI.SS.FF AM/PM'?我试过了,它似乎没有用。 就用我展示的。在格式掩码中包含 AM 或 PM(不是两者)将识别字符串 vakue 中的 AM 或 PM。 查看之前的评论 - HR 已经是带有时区的时间戳,因此您不需要或不需要to_timestamp()
或from_tz()
。我不明白你想做什么。问题是关于您想将其视为时间戳的字符串值,而不是关于已经时间戳的内容。【参考方案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);
【讨论】:
如果我想做 HR = from_TZ(TO_TIMESTAMP((HR) - (1/24), 'UTC') 怎么办?我尝试这个时出错。 Sind HR 是一个TIMESTAMP WITH TIME ZONE
数据类型,查询实际上是 SYS_EXTRACT_UTC(HR) = SYS_EXTRACT_UTC(FROM_TZ(TO_TIMESTAMP('15-JAN-17 05.00.00.000000000 AM'), SESSIONTIMEZONE) - (1/24))
- 这就是您需要的吗?
在没有明确格式定义的情况下使用TO_TIMESTAMP()
总是一个坏主意。
@WernfriedDomscheit 是的,你的建议是对的,谢谢你的提醒
所以我要做的是获取一个转换后的值(HR 中出现值的前一小时)。我试过 /*select hr, hr - (1/24) as CONVERTED from value */以上是关于当数据类型为 TIMESTAMP 和 TIMEZONE 时如何获取前一小时的值的主要内容,如果未能解决你的问题,请参考以下文章
数据库字段类型timeStamp应对应.net实体类的啥类型???
java中如何将“2014-07-07”保存到数据类型为Timestamp类型的数据库中