在 Snowflake JOIN 条件下强制使用 UTC 时间

Force UTC time in Snowflake JOIN condition

我有一个设置

  1. 具有类型 TIMESTAMP_LTZ (consumption_date) 的栏的登陆 table。包括时区 +02:00
  2. 从着陆读取的视图(landing_view)table
  3. 从具有类型 TIMESTAMP_NTZ (SOURCE_TIMESTAMP) 字段的 table 读取的视图 (raw_data),但值本身采用 UTC 时间.

我必须使用 consumption_date 和 SOURCE_TIMESTAMP 将 landing_view 中的数据连接到 raw_data 中的数据。

SELECT l.ID, l.consumption_date, l.RUN_TIME, r.DISPLAY_NAME, r.source_timestamp, r.value_as_double
FROM "raw_data" r
JOIN "landing_view" l
ON r.SOURCE_TIMESTAMP >= DATEADD(second,120, convert_timezone('UTC',l.consumption_date))
  and r.SOURCE_TIMESTAMP < DATEADD(second,1000, convert_timezone('UTC',l.consumption_date))

我的问题是 convert_timezone 命令似乎根本不影响连接子句,而是使用 LTZ 类型 (+02:00) 中包含的本地时间进行连接。

如果我使用 convert_timezone 是 select,如果工作正常,但对于 JOIN 则不行。

有什么方法可以告诉 snowflake 在连接中使用 UTC?

这取决于您的时区设置。请参阅下面的示例。

如果时区是 UTC:

alter session set TIMEZONE = 'UTC';
select 
    -- 2AM UTC
    '2021-01-02 02:00:00'::timestamp_ntz as SOURCE_TIMESTAMP,
    -- 1AM UTC / 12PM Australia/Melbourne time / 1 hour before SOURCE_TIMESTAMP
    '2021-01-02 12:00:00 +1100'::timestamp_ltz as CONSUMPTION_DATE,
    -- so add one hour to CONSUMPTION_DATE should equal to SOURCE_TIMESTAMP
    SOURCE_TIMESTAMP = DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as is_equal
;

+-------------------------------+-------------------------------+----------+
| SOURCE_TIMESTAMP              | CONSUMPTION_DATE              | IS_EQUAL |
|-------------------------------+-------------------------------+----------|
| 2021-01-02 02:00:00.000000000 | 2021-01-02 01:00:00.000 +0000 | True     |
+-------------------------------+-------------------------------+----------+

但是,如果您将 TIMEZONE 设置更改为另一个时区,结果将有所不同:

alter session set TIMEZONE = 'Australia/Melbourne';
select 
    -- 2AM UTC
    '2021-01-02 02:00:00'::timestamp_ntz as SOURCE_TIMESTAMP,
    -- 1AM UTC / 12PM Australia/Melbourne time / 1 hour before SOURCE_TIMESTAMP
    '2021-01-02 12:00:00 +1100'::timestamp_ltz as CONSUMPTION_DATE,
    -- so add one hour to CONSUMPTION_DATE should equal to SOURCE_TIMESTAMP
    SOURCE_TIMESTAMP = DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as is_equal
;

+-------------------------------+-------------------------------+----------+
| SOURCE_TIMESTAMP              | CONSUMPTION_DATE              | IS_EQUAL |
|-------------------------------+-------------------------------+----------|
| 2021-01-02 02:00:00.000000000 | 2021-01-02 12:00:00.000 +1100 | False    |
+-------------------------------+-------------------------------+----------+

由于您 SOURCE_TIMESTAMP 存储了 UTC 值,您应该更改您的 TIMEZONE 设置以匹配它。

顺便说一句,在 DATEADD 中加入 CONVERT_TIMEZONE 是多余的,因为它只是增加了额外的操作,但没有任何效果。请参阅以下示例:

select 
    -- 1AM UTC / 9AM Australia/Perth time / 1 hour before SOURCE_TIMESTAMP
    '2021-01-02 09:00:00 +0800'::timestamp_ltz as CONSUMPTION_DATE,
    DATEADD(hour, 1, CONSUMPTION_DATE) as no_convert_tz,
    DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as convert_tz,
    no_convert_tz = convert_tz
;

+-------------------------------+-------------------------------+-------------------------------+----------------------------+
| CONSUMPTION_DATE              | NO_CONVERT_TZ                 | CONVERT_TZ                    | NO_CONVERT_TZ = CONVERT_TZ |
|-------------------------------+-------------------------------+-------------------------------+----------------------------|
| 2021-01-02 12:00:00.000 +1100 | 2021-01-02 13:00:00.000 +1100 | 2021-01-02 02:00:00.000 +0000 | True                       |
+-------------------------------+-------------------------------+-------------------------------+----------------------------+

您可以看到最后一列 returns 正确。