You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WHERE子句中使用FROM_TZ未返回正确结果,为何SQL未返回2行?

为何以下SQL未返回2行?
WITH dates AS (
    SELECT TO_DATE('17/01/2023 11:42', 'dd/mm/yyyy hh24:mi') dst_time FROM dual 
    UNION ALL 
    SELECT TO_DATE('17/01/2023 17:35', 'dd/mm/yyyy hh24:mi') dst_time FROM dual
)
SELECT FROM_TZ(CAST(TO_DATE('17/01/2023 00:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT' begin_time,  
       FROM_TZ(CAST(to_date('17/01/2023 17:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT' end_time,
      dst_time
FROM dates
WHERE dst_time BETWEEN FROM_TZ(CAST(to_date('17/01/2023 00:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT' 
                    AND FROM_TZ(CAST(to_date('17/01/2023 17:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT'  
ORDER BY dst_time DESC;

注意:FROM_TZ(CAST(to_date('17/01/2023 17:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT'返回的是22:00,但查询结果未返回17/01/2023 17:35这一行,十分奇怪。


问题根源

问题出在数据类型不匹配引发的时区转换逻辑偏差:

  • dst_time是DATE类型,Oracle的DATE无时区属性,本质存储的是当前会话时区的时间戳。
  • WHERE子句中BETWEEN两端是TIMESTAMP WITH TIME ZONE类型(已转换为GMT时区)。当DATE与带时区的TIMESTAMP比较时,Oracle会自动将DATE转换为当前会话时区的TIMESTAMP WITH TIME ZONE,再与GMT时间做对比。

举个实际场景:如果你的会话时区是US/EASTERN,那么TO_DATE('17/01/2023 17:35', ...)会被转换为17/01/2023 17:35 US/EASTERN,转成GMT后是17/01/2023 22:35 GMT,这明显大于BETWEEN的上限22:00 GMT,因此该行被过滤。

解决方案

要保证比较逻辑准确,需让两边的时间类型及时区统一,两种常用处理方式:

方法1:将dst_time转换为GMT时区的带时区时间

假设dst_time实际存储的是US/EASTERN时区的时间,修改WHERE子句:

WHERE FROM_TZ(CAST(dst_time AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT'
      BETWEEN FROM_TZ(CAST(to_date('17/01/2023 00:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT' 
          AND FROM_TZ(CAST(to_date('17/01/2023 17:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'GMT'

方法2:将BETWEEN两端的GMT时间转换为US/EASTERN时区的DATE

既然dst_time是US/EASTERN时区的DATE,直接把过滤条件转成对应时区的时间:

WHERE dst_time
      BETWEEN CAST(FROM_TZ(CAST(to_date('17/01/2023 00:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'US/EASTERN' AS DATE)
          AND CAST(FROM_TZ(CAST(to_date('17/01/2023 17:00:00','dd/mm/yyyy hh24:mi:ss') AS TIMESTAMP), 'US/EASTERN') AT TIME ZONE 'US/EASTERN' AS DATE)

(注:如果过滤条件原本就是基于US/EASTERN时区的时间,可直接简化为TO_DATE('17/01/2023 00:00:00', ...)和TO_DATE('17/01/2023 17:00:00', ...))

内容的提问来源于stack exchange,提问作者NatureLover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:20:41