カテゴリ:

クエリ構文

AT | BEFORE

AT または BEFORE 句は、Snowflake Time Travelに使用されます。クエリでは、テーブル名の直後の FROM 句で指定され、オブジェクトの履歴データが要求される過去のポイントを決定します。

  • AT キーワードは、指定されたパラメーターに等しいタイムスタンプを持つステートメントまたはトランザクションによる変更がリクエストに含まれることを指定します。

  • BEFORE キーワードは、リクエストが指定されたパラメーターの直前のポイントを参照するように指定します。このポイントは、クエリー ID で識別されるステートメントが完了する直前です。詳細については、 BEFORE 句の使用 をご参照ください。

詳細については、 Time Travelの理解と使用 をご参照ください。

こちらもご参照ください。

FROM

構文

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

パラメーター

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日以上経過したクエリを参照している場合は、次のエラーが返されます。

Error: statement <query_id> not found

この制限を回避するには、参照されるクエリのタイムスタンプを使用します。

STREAM => 'name'

クエリされたテーブルまたはビューの既存のストリームに対する識別子(つまり、名前)を指定します。ストリーム内の現在のオフセットは、ソースオブジェクトの変更データを返すための AT 時点として使用されます。

このキーワードは、ストリームを作成(CREATE STREAM を使用)または変更データをクエリ( CHANGES 句を使用)するの場合にのみサポートされます。例については、次のトピックを参照してください。

AT TIMESTAMP パラメーターの使用

AT 句では、 TIMESTAMP キーワードの後に、タイムスタンプを表す文字列と、オプションで TIMESTAMP、 TIMESTAMP_TZ、 TIMESTAMP_LTZ、 TIMESTAMP_NTZ データ型への明示的なキャストを指定することができます。次の例はすべて有効です。

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

明示的なキャストが指定されていない場合、 AT 句のタイムスタンプは、 UTC のタイムゾーン (TIMESTAMP_NTZと同等)のタイムスタンプとして扱われます。明示的なキャストで TIMESTAMP データ型を使用すると、 日付と時刻のデータ型 で説明したように、値が TIMESTAMP_NTZ 値として扱われる場合があります。

タイムスタンプはセッションの現在のタイムゾーンおよび TIMESTAMP_TYPE_MAPPING パラメータの値を基準に解釈されるため、選択した明示的なキャストはTime Travelクエリの結果に影響されます。この動作の詳細については、 UTC タイムゾーン以外のセッションでのTime Travelデータのクエリ を参照してください。

例えば、現在のタイムゾーンが America/Los_Angeles で、 TIMESTAMP_TYPE_MAPPING が TIMESTAMP_NTZ に設定されている SQL セッションでクエリを実行しているとします。例えば、テーブルを作成し、そこに2つの行を挿入します。

CREATE OR REPLACE TABLE tt1 (c1 INT, c2 INT);
INSERT INTO tt1 VALUES(1,2);
INSERT INTO tt1 VALUES(2,3);
Copy

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  |
+-------------------------------+------+-------+---------------+----------------+

created_on 列のタイムゾーンオフセットに注目します。5分後に、もう1行挿入します。

INSERT INTO tt1 VALUES(3,4);
Copy

ここで、次のTime Travelクエリを実行します。最初の2行が返されるはずです。

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.

クエリー失敗します。セッションのタイムゾーンは UTC であり、 TIMESTAMP への明示的なキャストはそのタイムゾーンに従うからです。そのため、テーブルは指定されたタイムスタンプよりも に作成されたものとみなされます。この問題を解決するには、 TIMESTAMP_LTZ (ローカルタイムゾーン)に明示的にキャストしてクエリを再実行します。

SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:29:00'::TIMESTAMP_LTZ);
Copy
+----+----+
| C1 | C2 |
|----+----|
|  1 |  2 |
|  2 |  3 |
+----+----+

予想どおり、挿入された最初の2行がクエリから返されます。最後に同じクエリを、少し後のタイムスタンプを指定して実行します。

SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:31:00'::TIMESTAMP_LTZ);
Copy
+----+----+
| C1 | C2 |
|----+----|
|  1 |  2 |
|  2 |  3 |
|  3 |  4 |
+----+----+

このクエリは、指定されたタイムスタンプを持つ3行すべてを返します。

BEFORE 句の使用

BEFORE 句の STATEMENT パラメータは、クエリ ID を参照する必要があります。Time Travelが使用する過去の時点は、ステートメントの開始前ではなく、そのクエリ ID のステートメントの完了直前です。同時実行クエリがステートメントの開始と終了の間にデータの変更をコミットした場合、これらの変更は結果に含まれます。

たとえば、以下のステートメントは、テーブル my_table の2つのスレッドで並行して実行されます。

時間

スレッド

操作

フェーズ

説明

t1

1

INSERT INTO my_table(id) VALUE(1)

開始

必要なチェックを実行して挿入を開始します。

t2

1

INSERT INTO my_table(id) VALUE(1)

終了

更新された my_table を挿入します。

t3

1

DELETE FROM my_table

開始

削除は、削除する記録のリストを識別子で指定します(id=1)。

t4

2

INSERT INTO my_table(id) VALUE(2)

開始

必要なチェックを実行して挿入を開始します。

t5

2

INSERT INTO my_table(id) VALUE(2)

終了

更新された my_table を挿入します。

t6

2

SELECT * FROM my_table

終了

スレッド 2 は、 my_table から行を選択します。結果にはすべての行(id=1、id=2)が含まれます。

t7

1

DELETE FROM my_table

終了

削除は、スレッド 1 (id=1)で削除ステートメントが開始された時刻 t3 より前に存在した古い記録をすべて削除して my_table を更新します。

t8

1

SELECT * FROM my_table BEFORE(STATEMENT => LAST_QUERY_ID())

終了

SELECT ステートメントは、Time Travelを使用して削除操作の完了前からの履歴データを取得します。結果には、スレッド 2 (id=1、id=2)で同時に発生した2番目の挿入ステートメントからの行が含まれます。

回避策として、ステートメント開始直前の時点を指定する TIMESTAMP パラメーターを使用することができます。

使用上の注意

  • Snowflakeのデータは、システム時間の正確な値とわずかに異なる可能性があるタイムスタンプによって識別されます。

  • TIMESTAMP または OFFSET の値は定数式でなければなりません。

  • TIMESTAMP の最小時間解像度はミリ秒です。

  • 要求されたデータがTime Travel保持期間(デフォルトは1日)を超えている場合、ステートメントは失敗します。

    さらに、要求されたデータがTime Travel保持期間内であっても、履歴データが利用できない場合(保持期間が延長された場合など)、ステートメントは失敗します。

  • 指定されたTime Travel時間がオブジェクトが作成された時点またはそれ以前の場合、ステートメントは失敗します。 AT TIMESTAMP パラメーターの使用 をご参照ください。

  • 履歴テーブルデータにアクセスすると、その結果にはテーブルの現在の定義に基づく列やデフォルト値などが含まれます。マテリアライズドビュー以外についても同様です。たとえば、テーブルを変更して列を追加した場合に、列が追加された時点より前の履歴データをクエリすると、新しい列を含む結果が返されます。

  • 履歴データには、現在のデータと同じアクセス制御要件があります。変更は遡及的に適用されます。

  • AT および BEFORE 句は、 CTE からの履歴データの選択には対応していません。

    たとえば、次のクエリはサポートされていません。

    WITH mycte AS
      (SELECT mytable.* FROM mytable)
    SELECT * FROM mycte AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ);
    
    Copy

    しかし、これらの句は、 WITH 句のクエリでサポートされています。たとえば、次のクエリはさぽーとされています。

    WITH mycte AS
      (SELECT * FROM mytable AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ))
    SELECT * FROM mycte;
    
    Copy
  • ハイブリッドテーブルに対するTime Travelクエリには、以下の制限があります:

    • AT 句では、 TIMESTAMP パラメーターのみがサポートされます。OFFSET、 STATEMENT、 STREAM パラメーターはサポートされません。

    • TIMESTAMP パラメーターの値は、同じデータベースに属するすべてのテーブルで同じでなければなりません。テーブルが異なるデータベースに属している場合は、 TIMESTAMP の値が異なる場合があります。

    • BEFORE 句はサポートされません。

トラブルシューティング

エラー

Time travel data is not available for table <tablename>

原因

場合によっては、これはタイムスタンプが期待される場所で文字列を使用することによって引き起こされます。

解決策

文字列をタイムスタンプにキャストします。

... AT(TIMESTAMP => '2018-07-27 12:00:00')               -- fails
... AT(TIMESTAMP => '2018-07-27 12:00:00'::TIMESTAMP)    -- succeeds
Copy

特定のタイムスタンプを使用して、テーブルから履歴データを選択します。TIMESTAMP パラメーターを使用する最初の2つの例では、 my_table は標準テーブルかハイブリッドテーブルになります。

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

5分前の時点でテーブルから履歴データを選択します。

SELECT * FROM my_table AT(OFFSET => -60*5) AS T WHERE T.flag = 'valid';
Copy

テーブルから履歴データを選択しますが、指定したトランザクションによる変更は含まれません。

SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
Copy

指定されたトランザクションから生じるテーブルデータの差を返します。

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

以下の例では、同じデータベース内の2つのテーブル(片方はハイブリッドテーブル)に対してTime Travel結合クエリを実行しています。両方のテーブルに同じ TIMESTAMP 式を使用する必要があります。

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