- 类别:
AT | BEFORE¶
AT 或 BEFORE 子句用于 Snowflake Time Travel。在查询中,它在 FROM 子句中紧接在表名之后指定,并确定请求对象历史数据的过去时间点:
AT 关键字指定请求包含时间戳等于指定参数的语句或事务所做的任何变更。
BEFORE 关键字指定请求引用紧挨着指定参数之前的点。此时间点恰好位于由其查询 ID 标识的语句完成之前。有关更多信息,请参阅 使用 BEFORE 子句。
您可以使用相同的语法来克隆对象;请参阅 CREATE <object> ... CLONE。如果您没有为克隆指定时间点,则克隆默认为当前对象的状态(CURRENT_TIMESTAMP 值)。
有关更多信息,请参阅 了解和使用 Time Travel。
- 另请参阅:
语法¶
参数¶
TIMESTAMP => timestamp指定要用于 Time Travel 的确切日期和时间。该值必须显式转换为 TIMESTAMP、TIMESTAMP_LTZ、TIMESTAMP_NTZ 或 TIMESTAMP_TZ 数据类型。
如未指定显式转换,AT 子句中的时间戳会被视为采用 UTC 时区的时间戳(相当于 TIMESTAMP_NTZ)。为显式强制转换使用 TIMESTAMP 数据类型也可能导致值被视为 TIMESTAMP_NTZ 值。有关详细信息,请参阅 日期和时间数据类型。
OFFSET => time_difference指定自当前时间开始的、要用于 Time Travel 的时间差值(以秒为单位),其格式为
-N,其中N可以是整数或算术表达式(例如,-120为 120 秒、-30*60为 1800 秒或 30 分钟)。STATEMENT => id指定要用作 Time Travel 参考点的语句的查询 ID。此参数支持以下某一类型的任意语句:
DML(例如 INSERT、UPDATE、DELETE)
TCL(BEGIN、COMMIT 事务)
SELECT
查询 ID 必须引用过去 14 天内执行的查询。如果查询 ID 引用的查询超过 14 天,则返回以下错误:
若要解决此限制,请使用引用查询的时间戳。
STREAM => 'name'指定已查询的表或视图上现有流的标识符(即名称)。流中的当前偏移用作返回源对象的变更数据的
AT或BEFORE时间点。只有在创建流(使用 CREATE STREAM)或查询更改数据(使用 CHANGES 子句)时才支持此关键字。有关示例,请参阅以下主题。
使用 AT TIMESTAMP 参数¶
在 AT 子句中,您可以指定 TIMESTAMP 关键字后接一个表示时间戳的字符串,以及一个到 TIMESTAMP、TIMESTAMP_TZ、TIMESTAMP_LTZ 或 TIMESTAMP_NTZ 数据类型的可选显式转换。以下示例均有效:
如未指定显式转换,AT 子句中的时间戳会被视为采用 UTC 时区的时间戳(相当于 TIMESTAMP_NTZ)。为显式强制转换使用 TIMESTAMP 数据类型也可能导致值被视为 TIMESTAMP_NTZ 值,如 日期和时间数据类型 中所述。
您选择的显式转换会影响 Time Travel 查询的结果,因为时间戳是根据会话的当前时区和 TIMESTAMP_TYPE_MAPPING 参数的值解释的。有关此行为的更多详细信息,请参阅 在使用非 UTC 时区的会话中查询 Time Travel 数据 (https://community.snowflake.com/s/article/Querying-time-travel-data-in-a-session-with-a-non-UTC-timezone)。
例如,您正在当前时区为 America/Los_Angeles 且 TIMESTAMP_TYPE_MAPPING 设置为 TIMESTAMP_NTZ 的 SQL 会话中运行查询。创建一个表并立即插入两行:
使用以下 SHOW TABLES 命令检查表的创建时间:
请注意 created_on 列中的时区偏移。在五分钟后插入另一行:
现在运行以下 Time Travel 查询,它本该返回前两行:
查询失败,因为会话的时区是 UTC,并且显式转换为采用该时区的 TIMESTAMP。因此,假定该表是在指定时间戳 之后 创建的。要解决此问题,请在显式转换为 TIMESTAMP_LTZ(当地时区)的情况下再次运行查询:
正如预期的那样,查询返回所插入的前两行。最后运行相同的查询,但指定稍晚的时间戳:
给定较晚的时间戳,此查询会返回全部三行。
使用 BEFORE 子句¶
BEFORE 子句的 STATEMENT 参数必须引用查询 ID。Time Travel 使用的过去点正好在该查询 ID 语句完成之前,而不是在语句开始之前。如果并发查询在语句开始和结束之间提交了对数据的修改,则这些更改会包含在结果中。
例如,以下语句在两个独立的线程中在 my_table 表上同时执行:
时间 |
线程 |
操作 |
阶段 |
描述 |
|---|---|---|---|---|
|
1 |
INSERT INTO my_table(id) VALUE(1) |
开始时间 |
插入通过执行必要的检查开始执行。 |
|
1 |
INSERT INTO my_table(id) VALUE(1) |
结束时间 |
插入更新后的 |
|
1 |
DELETE FROM my_table |
开始时间 |
删除操作标识要删除的记录列表 (id=1)。 |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
开始时间 |
插入通过执行必要的检查开始执行。 |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
结束时间 |
插入更新后的 |
|
2 |
SELECT * FROM my_table |
结束时间 |
线程 |
|
1 |
DELETE FROM my_table |
结束时间 |
当删除语句在线程 |
|
1 |
SELECT * FROM my_table BEFORE(STATEMENT => LAST_QUERY_ID()) |
结束时间 |
SELECT 语句使用 Time Travel 来检索删除操作完成前的历史数据。结果包含来自第 2 条插入语句的行,该语句在线程 |
作为解决方法,可以使用 TIMESTAMP 参数指定正好在语句开始之前的时间点。
使用说明¶
Snowflake 中的数据由时间戳标识,时间戳可能与系统时间的确切值略有不同。
TIMESTAMP 或 OFFSET 的值必须是常量表达式。
TIMESTAMP 的最小时间分辨率为毫秒。
如果请求的数据超出了 Time Travel 保留期(默认值为 1 天),则语句将失败。
此外,如果请求的数据在 Time Travel 保留期内,但没有可用的历史数据(例如保留期已延长的情况),则语句将失败。
如果指定的 Time Travel 时间在创建对象的时间点或之前,则语句将失败。请参阅 使用 AT TIMESTAMP 参数。
访问历史表数据时,结果包含表当前定义中的列和默认值等。非物化视图也是如此。例如,如果更改表以添加列,则查询在添加列的时间点之前的历史数据会返回包含新列的结果。
历史数据与当前数据具有相同的访问控制要求。任何更改都具有追溯性。
AT 和 BEFORE 子句不支持通过 CTE 选择历史数据。
例如,不支持以下查询:
不过,在 WITH 子句的查询中支持这些子句。例如,支持以下查询:
针对混合表的 Time Travel 查询具有以下限制:
TIMESTAMP 子句仅支持 AT 参数。不支持 OFFSET、STATEMENT 和 STREAM 参数。
对于属于同一数据库的所有表,TIMESTAMP 参数的值必须相同。如果表属于不同的数据库,则可以使用不同的 TIMESTAMP 值。
不支持 BEFORE 子句。
CREATE DATABASE ...CLONE 和 CREATE SCHEMA ...CLONE 命令如果使用 Time Travel 并使用 STATEMENT 参数,则在指定数据库中存在任何混合表时,它会返回错误。该错误提示您使用 IGNORE HYBRID TABLES 参数 运行命令。使用此参数时,该命令将创建克隆数据库或架构,但会跳过任何混合表。
故障排除¶
错误 |
|
|---|---|
原因 |
在某些情况下,这是由于使用需要时间戳的字符串引起的。 |
解决方案 |
将字符串转换为时间戳。 |
示例¶
使用特定时间戳从表中选择历史数据。在前两个使用 TIMESTAMP 参数的示例中,my_table 可以是标准表或混合表。替换保留期内的最新日期、时间或时间戳。
从表中选择截至 5 分钟前的历史数据:
从表中选择历史数据,但不包括指定事务所做的任何更改:
返回指定事务导致的表数据差异:
以下示例对同一数据库中的两个表运行 Time Travel 联接查询,其中一个表是混合表。两个表必须使用相同的 TIMESTAMP 表达式。替换保留期内的最新日期、时间或时间戳。