我正在尝试从oracle SQL表中提取距特定时间不超过30分钟的行。但是时间不会存储为日期字段,而是以“ 2019-04-04T21:32:38 + 0000”格式存储在VARCHAR2字段中
在SQL查询中是否可以做到这一点?
尝试花费时间并将其转换,但我只能得到时间戳,而且我不知道如何正确地补偿时间
答案 0 :(得分:2)
您需要做的第一件事是将字符串转换为日期时间类型。由于您的字符串具有时区值,因此会将其转换为TIMESTAMP WITH TIME ZONE
数据类型。
to_timestamp_tz( '2019-04-04T21:32:38+0000', 'yyyy-mm-dd"T"hh24:mi:sstzhtzm')
这给了我“ 04-APR-19 09.32.38.000000000 PM GMT”,它是日期/时间值,而不是字符值。
您说您正在将其与其他值进行比较,但是没有提供任何详细信息,因此我无法再进一步了。
此外,请尽量不要将日期/时间存储为varchar2s
。只会造成问题。
答案 1 :(得分:0)
您无需转换为UTC。如@eaolson所示,您可以将您需要的字符串转换为带有时区值的时间戳。然后,您可以将其与具有时区值的任何其他时间戳直接进行比较-Oracle将无形地处理任何调整。当然,您可以转换为UTC,但不需要。
我不确定如何将当前时间转换为TZ
systimestamp
和current_timestamp
都已经具有时区信息。
因此,为了展示一些查询的一致性,我们将它们紧密结合在一起:
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF1 TZR';
select current_timestamp, current_timestamp at time zone 'GMT' as now_as_gmt
from dual;
CURRENT_TIMESTAMP NOW_AS_GMT
----------------------------------- -------------------------
2019-04-15 16:02:29.6 EUROPE/LONDON 2019-04-15 15:02:29.6 GMT
并在截止30分钟之前和之后使用CTE生成一些数据:
-- CTE for sample data
with your_table (some_time) as (
select '2019-04-04T21:32:38+0000' from dual
union all
select to_char(current_timestamp at time zone 'Africa/Nairobi'
- interval '30' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
union all
select to_char(current_timestamp at time zone 'Europe/London'
- interval '29' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
union all
select to_char(current_timestamp at time zone 'America/New_York'
- interval '28' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
union all
select to_char(current_timestamp at time zone 'UTC'
- interval '27' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
)
-- query
select some_time,
to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') some_time_as_tstz,
to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') at time zone 'GMT' some_time_as_gmt
from your_table;
SOME_TIME SOME_TIME_AS_TSTZ SOME_TIME_AS_GMT
------------------------ ---------------------------- -------------------------
2019-04-04T21:32:38+0000 2019-04-04 21:32:38.0 GMT 2019-04-04 21:32:38.0 GMT
2019-04-15T17:32:29+0300 2019-04-15 17:32:29.0 +03:00 2019-04-15 14:32:29.0 GMT
2019-04-15T15:33:29+0100 2019-04-15 15:33:29.0 +01:00 2019-04-15 14:33:29.0 GMT
2019-04-15T10:34:29-0400 2019-04-15 10:34:29.0 -04:00 2019-04-15 14:34:29.0 GMT
2019-04-15T14:35:29+0000 2019-04-15 14:35:29.0 GMT 2019-04-15 14:35:29.0 GMT
您可以看到已转换为时间戳的字符串的实际值及其GMT等效项-再次,不需要,仅用于视觉验证。
然后,您可以在过滤器中使用current_timestamp
或systimestamp
,将其向后调整30分钟:
-- same CTE omitted
select some_time,
to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') some_time_as_tstz,
to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') at time zone 'GMT' some_time_as_gmt
from your_table
where to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM')
> current_timestamp - interval '30' minute;
SOME_TIME SOME_TIME_AS_TSTZ SOME_TIME_AS_GMT
------------------------ ---------------------------- -------------------------
2019-04-15T15:33:29+0100 2019-04-15 15:33:29.0 +01:00 2019-04-15 14:33:29.0 GMT
2019-04-15T10:34:29-0400 2019-04-15 10:34:29.0 -04:00 2019-04-15 14:34:29.0 GMT
2019-04-15T14:35:29+0000 2019-04-15 14:35:29.0 GMT 2019-04-15 14:35:29.0 GMT
排除了过去30分钟或更长时间的两个CTE行。比较时会考虑它们的实际时区或您的会话/系统的时区,而不必将任何内容显式转换为任何特定的时区。
提前30分钟或比当前时间戳短
然后在一个时间范围内检查您的值:
where initial_proc_etr >= current_timestamp - interval '30' minute;
and initial_proc_etr < current_timestamp + interval '30' minute
如您在评论中所述,假定该列具有时区成分。