- Kategorien:
AT | BEFORE¶
Die AT- oder BEFORE-Klausel wird für Snowflake Time Travel verwendet. In einer Abfrage wird sie in der FROM-Klausel unmittelbar nach dem Tabellennamen angegeben und bestimmt den Punkt in der Vergangenheit, ab dem historische Daten für das Objekt angefordert werden:
Das Schlüsselwort AT gibt an, dass die Anforderung alle Änderungen beinhaltet, die durch eine Anweisung oder Transaktion mit einem Zeitstempel gleich dem angegebenen Parameter vorgenommen werden.
Das Schlüsselwort BEFORE gibt an, dass sich die Anforderung auf einen Zeitpunkt unmittelbar vor dem angegebenen Parameter bezieht. Dieser Zeitpunkt liegt kurz vor dem Abschluss der Anweisung, die durch die Abfrage-ID gekennzeichnet ist. Weitere Informationen dazu finden Sie unter Verwenden der BEFORE-Klausel.
Weitere Informationen dazu finden Sie unter Verstehen und Verwenden von Time Travel.
- Siehe auch:
Syntax¶
SELECT ...
FROM ...
{
AT( { TIMESTAMP => <timestamp> | OFFSET => <time_difference> | STATEMENT => <id> | STREAM => '<name>' } ) |
BEFORE( STATEMENT => <id> )
}
[ ... ]
Parameter¶
TIMESTAMP => timestamp
Gibt ein genaues Datum und eine genaue Zeit für Time Travel an. Der Wert muss explizit in einen TIMESTAMP-, TIMESTAMP_LTZ-, TIMESTAMP_NTZ- oder TIMESTAMP_TZ- Datentyp umgewandelt werden.
Wenn kein explizites Umwandeln angegeben wird, wird der Zeitstempel in der AT-Klausel als Zeitstempel mit der Zeitzone UTC behandelt (entspricht TIMESTAMP_NTZ). Die Verwendung des Datentyps TIMESTAMP für ein explizites Umwandeln kann auch dazu führen, dass der Wert als TIMESTAMP_NTZ-Wert behandelt wird. Weitere Details dazu finden Sie unter Datentypen für Datum und Uhrzeit.
OFFSET => time_difference
Gibt für Time Travel die Differenz in Sekunden von der aktuellen Zeit im Format
-N
an, wobeiN
eine Ganzzahl oder ein arithmetischer Ausdruck sein kann (z. B. entspricht-120
120 Sekunden;-30*60
entspricht 1.800 Sekunden oder 30 Minuten).STATEMENT => id
Gibt die Abfrage-ID einer Anweisung an, die als Referenzpunkt für Time Travel verwendet werden soll. Dieser Parameter unterstützt alle Anweisungen eines der folgenden Typen:
DML (z. B. INSERT, UPDATE, DELETE)
TCL (BEGIN, COMMIT-Transaktion)
SELECT
Die Abfrage-ID muss auf eine Abfrage verweisen, die innerhalb der letzten 14 Tage ausgeführt wurde. Wenn die Abfrage-ID auf eine Abfrage verweist, die älter als 14 Tage ist, wird der folgende Fehler zurückgegeben:
Error: statement <query_id> not found
Um diese Einschränkung zu umgehen, verwenden Sie den Zeitstempel für die referenzierte Abfrage.
STREAM => 'name'
Gibt den Bezeichner (d. h. den Namen) eines vorhandenen Streams auf der abgefragten Tabelle oder Ansicht an. Der aktuelle Offset im Stream wird als
AT
-Zeitpunkt für die Rückgabe von Änderungsdaten für das Quellobjekt verwendet.Dieses Schlüsselwort wird nur beim Erstellen eines Streams (mit CREATE STREAM) oder beim Abfragen von Änderungsdaten (mit der CHANGES-Klausel) unterstützt. Beispiele dazu finden Sie unter diesen Themen.
Verwendung des Parameters AT TIMESTAMP¶
In der Klausel AT können Sie das Schlüsselwort TIMESTAMP angeben, gefolgt von einer Zeichenfolge, die einen Zeitstempel darstellt, und einem optionalen expliziten Cast auf den Datentyp TIMESTAMP, TIMESTAMP_TZ, TIMESTAMP_LTZ oder TIMESTAMP_NTZ. Die folgenden Beispiele sind alle gültig:
AT ( TIMESTAMP => '2024-06-05 12:30:00'::TIMESTAMP_LTZ )
AT ( TIMESTAMP => '2024-06-05 12:30:00'::TIMESTAMP )
AT ( TIMESTAMP => '2024-06-05 12:30:00' )
Wenn kein explizites Umwandeln angegeben wird, wird der Zeitstempel in der AT-Klausel als Zeitstempel mit der Zeitzone UTC behandelt (entspricht TIMESTAMP_NTZ). Die Verwendung des Datentyps TIMESTAMP für ein explizites Umwandeln kann auch dazu führen, dass der Wert wie ein TIMESTAMP_NTZ-Wert behandelt wird, wie in Datentypen für Datum und Uhrzeit beschrieben.
Die von Ihnen gewählte explizite Umwandlung wirkt sich auf die Ergebnisse von Time Travel-Abfragen aus, da Zeitstempel in Bezug auf die aktuelle Zeitzone der Sitzung und den Wert des Parameters TIMESTAMP_TYPE_MAPPING interpretiert werden. Weitere Informationen zu dieser Verhaltensweise finden Sie unter Abfrage von Time Travel-Daten in einer Sitzung mit einer Nicht-UTC-Zeitzone.
Sie führen zum Beispiel Abfragen in einer SQL-Sitzung aus, in der die aktuelle Zeitzone America/Los_Angeles
ist und TIMESTAMP_TYPE_MAPPING auf TIMESTAMP_NTZ
eingestellt ist. Erstellen Sie eine Tabelle und fügen Sie sofort zwei Zeilen ein:
CREATE OR REPLACE TABLE tt1 (c1 INT, c2 INT);
INSERT INTO tt1 VALUES(1,2);
INSERT INTO tt1 VALUES(2,3);
Überprüfen der Erstellungszeit der Tabelle mit dem Befehl SHOW TABLES:
SHOW TERSE TABLES LIKE 'tt1';
+-------------------------------+------+-------+---------------+----------------+
| created_on | name | kind | database_name | schema_name |
|-------------------------------+------+-------+---------------+----------------|
| 2024-06-05 15:25:35.557 -0700 | TT1 | TABLE | TRAVEL_DB | TRAVEL_SCHEMA |
+-------------------------------+------+-------+---------------+----------------+
Beachten Sie den Zeitzonenoffset in der Spalte created_on
. Fünf Minuten später fügen Sie eine weitere Zeile ein:
INSERT INTO tt1 VALUES(3,4);
Führen Sie nun die folgende Time Travel-Abfrage in der Erwartung aus, dass sie die ersten beiden Zeilen zurückgibt:
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:29:00'::TIMESTAMP);
000707 (02000): Time travel data is not available for table TT1. The requested time is either beyond the allowed time travel period or before the object creation time.
Die Abfrage schlägt fehl, weil die Zeitzone der Sitzung UTC ist und das explizite Umwandeln auf TIMESTAMP diese Zeitzone beachtet. Es wird daher angenommen, dass die Tabelle nach dem angegebenen Zeitstempel erstellt wurde. Um dieses Problem zu lösen, führen Sie die Abfrage noch einmal mit einer expliziten Umwandlung auf TIMESTAMP_LTZ (lokale Zeitzone) aus:
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:29:00'::TIMESTAMP_LTZ);
+----+----+
| C1 | C2 |
|----+----|
| 1 | 2 |
| 2 | 3 |
+----+----+
Wie erwartet gibt die Abfrage die ersten beiden Zeilen zurück, die eingefügt wurden. Führen Sie schließlich dieselbe Abfrage aus, geben Sie aber einen etwas späteren Zeitstempel an:
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:31:00'::TIMESTAMP_LTZ);
+----+----+
| C1 | C2 |
|----+----|
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
+----+----+
Diese Abfrage gibt alle drei Zeilen zurück, wenn Sie den späteren Zeitstempel angeben.
Verwenden der BEFORE-Klausel¶
Der STATEMENT-Parameter in der BEFORE-Klausel muss sich auf eine Abfrage-ID beziehen. Der von Time Travel verwendete Zeitpunkt in der Vergangenheit liegt kurz vor dem Abschluss der Anweisung für diese Abfrage-ID und nicht vor dem Beginn der Anweisung. Wenn bei gleichzeitigen Abfragen Änderungen an den Daten zwischen dem Beginn und dem Ende der Anweisung vorgenommen werden, werden diese Änderungen in Ihre Ergebnisse aufgenommen.
Beispielsweise werden die folgenden Anweisungen auf der Tabelle my_table
parallel in zwei separaten Threads ausgeführt:
Dauer |
Thread |
Operation |
Phase |
Beschreibung |
---|---|---|---|---|
|
1 |
INSERT INTO my_table(id) VALUE(1) |
Start |
INSERT beginnt die Ausführung mit der Durchführung der erforderlichen Prüfungen. |
|
1 |
INSERT INTO my_table(id) VALUE(1) |
Ende |
INSERT aktualisiert |
|
1 |
DELETE FROM my_table |
Start |
DELETE identifiziert die Liste der zu löschenden Datensätze (id=1). |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
Start |
INSERT beginnt die Ausführung mit der Durchführung der erforderlichen Prüfungen. |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
Ende |
INSERT aktualisiert |
|
2 |
SELECT * FROM my_table |
Ende |
Thread |
|
1 |
DELETE FROM my_table |
Ende |
DELETE aktualisiert |
|
1 |
SELECT * FROM my_table BEFORE(STATEMENT => LAST_QUERY_ID()) |
Ende |
SELECT verwendet Time Travel, um historische Daten aus der Zeit vor Abschluss der Löschoperation abzurufen. Die Ergebnisse enthalten die Zeile aus der 2. INSERT-Anweisung, die gleichzeitig in Thread |
Als Problemumgehung können Sie einen TIMESTAMP-Parameter verwenden, der einen Zeitpunkt kurz vor dem Beginn der Anweisung angibt.
Nutzungshinweise¶
Daten in Snowflake werden durch Zeitstempel identifiziert, die geringfügig vom genauen Wert der Systemzeit abweichen können.
Der Wert für TIMESTAMP oder OFFSET muss ein konstanter Ausdruck sein.
Die kleinste Zeitauflösung für TIMESTAMP sind Millisekunden.
Wenn die angeforderten Daten die Aufbewahrungsfrist von Time Travel überschreiten (der Standardwert ist 1 Tag), schlägt die Anweisung fehl.
Wenn außerdem die angeforderten Daten innerhalb der Aufbewahrungsfrist von Time Travel liegen, aber keine historischen Daten verfügbar sind (z. B. wenn der Aufbewahrungsfrist verlängert wurde), schlägt die Anweisung fehl.
Wenn die angegebene Time Travel-Zeit zu oder vor dem Zeitpunkt liegt, an dem das Objekt erstellt wurde, schlägt die Anweisung fehl. Siehe Verwendung des Parameters AT TIMESTAMP.
Wenn Sie auf historische Tabellendaten zugreifen, enthalten die Ergebnisse die Spalten, Standardwerte usw. aus der aktuellen Definition der Tabelle. Das Gleiche gilt für nicht materialisierte Ansichten. Wenn Sie beispielsweise eine Tabelle ändern, um eine Spalte hinzuzufügen, gibt die Abfrage nach historischen Daten vor dem Zeitpunkt, zu dem die Spalte hinzugefügt wurde, Ergebnisse zurück, die die neue Spalte enthalten.
Historische Daten haben die gleichen Anforderungen an die Zugriffssteuerung wie aktuelle Daten. Änderungen werden rückwirkend übernommen.
Die AT- und BEFORE-Klauseln unterstützen nicht die Auswahl historischer Daten aus einem CTE (Common Table Expression).
Folgende Abfrage wird beispielsweise nicht unterstützt:
WITH mycte AS (SELECT mytable.* FROM mytable) SELECT * FROM mycte AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ);
Diese Klauseln werden jedoch in der WITH-Klausel einer Abfrage unterstützt. Beispielsweise wird die folgende Abfrage unterstützt:
WITH mycte AS (SELECT * FROM mytable AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ)) SELECT * FROM mycte;
Time Travel-Abfragen auf Hybridtabellen haben die folgenden Beschränkungen:
Nur der TIMESTAMP-Parameter wird in der AT-Klausel unterstützt. Die Parameter OFFSET, STATEMENT und STREAM werden nicht unterstützt.
Der Wert des Parameters TIMESTAMP muss für alle Tabellen, die zur gleichen Datenbank gehören, gleich sein. Wenn die Tabellen zu verschiedenen Datenbanken gehören, können unterschiedliche TIMESTAMP-Werte verwendet werden.
Die BEFORE-Klausel wird nicht unterstützt.
Problembehandlung¶
Fehler |
Time travel data is not available for table <tablename>
|
---|---|
Ursache |
In einigen Fällen wird das Problem durch Verwendung einer Zeichenfolge verursacht, bei der ein Zeitstempel erwartet wird. |
Lösung |
Wandeln Sie die Zeichenfolge in einen Zeitstempel um. ... AT(TIMESTAMP => '2018-07-27 12:00:00') -- fails
... AT(TIMESTAMP => '2018-07-27 12:00:00'::TIMESTAMP) -- succeeds
|
Beispiele¶
Auswählen historischer Daten aus einer Tabelle mit einem bestimmten Zeitstempel: In den ersten beiden Beispielen, die den Parameter TIMESTAMP verwenden, könnte my_table
eine Standardtabelle oder eine Hybridtabelle sein.
SELECT * FROM my_table AT(TIMESTAMP => 'Wed, 26 Jun 2024 09:20:00 -0700'::TIMESTAMP_LTZ);
SELECT * FROM my_table AT(TIMESTAMP => TO_TIMESTAMP(1432669154242, 3));
Auswählen historischer Daten aus einer Tabelle von vor 5 Minuten:
SELECT * FROM my_table AT(OFFSET => -60*5) AS T WHERE T.flag = 'valid';
Auswählen historischer Daten aus einer Tabelle bis zu einer Änderung (Änderung exklusive), die von der angegebenen Transaktion vorgenommen wurde:
SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
Zurückgeben der Differenz in Tabellendaten zurück, die sich aus der angegebenen Transaktion ergibt:
SELECT oldt.* ,newt.*
FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS oldt
FULL OUTER JOIN my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS newt
ON oldt.id = newt.id
WHERE oldt.id IS NULL OR newt.id IS NULL;
Das folgende Beispiel führt eine Time Travel Join-Abfrage auf zwei Tabellen in derselben Datenbank aus, von denen eine Hybridtabelle ist. Für beide Tabellen muss derselbe TIMESTAMP-Ausdruck verwendet werden.
SELECT *
FROM db1.public.htt1
AT(TIMESTAMP => '2024-06-05 17:50:00'::TIMESTAMP_LTZ) h
JOIN db1.public.tt1
AT(TIMESTAMP => '2024-06-05 17:50:00'::TIMESTAMP_LTZ) t
ON h.c1=t.c1;