Kategorien:

Abfragesyntax

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:

FROM

Syntax

SELECT ...
FROM ...
  {
   AT( { TIMESTAMP => <timestamp> | OFFSET => <time_difference> | STATEMENT => <id> | STREAM => '<name>' } ) |
   BEFORE( STATEMENT => <id> )
  }
[ ... ]
Copy

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, wobei N 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' )
Copy

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);
Copy

Überprüfen der Erstellungszeit der Tabelle mit dem Befehl SHOW TABLES:

SHOW TERSE TABLES LIKE 'tt1';
Copy
+-------------------------------+------+-------+---------------+----------------+
| 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);
Copy

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);
Copy
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);
Copy
+----+----+
| 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);
Copy
+----+----+
| 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

t1

1

INSERT INTO my_table(id) VALUE(1)

Start

INSERT beginnt die Ausführung mit der Durchführung der erforderlichen Prüfungen.

t2

1

INSERT INTO my_table(id) VALUE(1)

Ende

INSERT aktualisiert my_table.

t3

1

DELETE FROM my_table

Start

DELETE identifiziert die Liste der zu löschenden Datensätze (id=1).

t4

2

INSERT INTO my_table(id) VALUE(2)

Start

INSERT beginnt die Ausführung mit der Durchführung der erforderlichen Prüfungen.

t5

2

INSERT INTO my_table(id) VALUE(2)

Ende

INSERT aktualisiert my_table.

t6

2

SELECT * FROM my_table

Ende

Thread 2 wählt Zeilen in my_table aus. Die Ergebnisse enthalten alle Zeilen (id=1, id=2).

t7

1

DELETE FROM my_table

Ende

DELETE aktualisiert my_table und löscht alle alten Datensätze, die vor dem Zeitpunkt t3 vorhanden waren, als die Löschanweisung in Thread 1 (id=1) begann.

t8

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 2 (id=1, id=2) erfolgte.

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);
    
    Copy

    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;
    
    Copy
  • 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
Copy

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);
Copy
SELECT * FROM my_table AT(TIMESTAMP => TO_TIMESTAMP(1432669154242, 3));
Copy

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';
Copy

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');
Copy

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;
Copy

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;
Copy