テンポラル テーブル

対象者:SQL Server 2016 (13.x) およびそれ以降のバージョン Azure SQL DatabaseAzure SQL Managed InstanceSQL Database in Microsoft Fabric

時間テーブル(システムバージョン対応時間テーブルとも呼ばれる)は、現在のデータだけでなく、任意の時点でテーブルに保存されたデータに関する情報を組み込みサポートするデータベース機能です。

システム バージョン管理されたテンポラル テーブルの使用を開始し、テンポラル テーブルの使用シナリオを確認してください。

システム バージョン管理されたテンポラル テーブルとは

システムバージョン対応時間テーブルは、データ変更の完全な履歴を保持し、時点分析を可能にするユーザーテーブルの一種です。 この種の時間テーブルはシステムバージョン制御時間テーブルと呼ばれ、システムは各行の有効期間(すなわちデータベース エンジン)を管理します。

すべてのテンポラル テーブルには、それぞれに datetime2 データ型が明示的に定義されている 2 つの列があります。 これらの列は 「周期 列」と呼ばれます。 データベース エンジンは、各行が変更された際の有効期間を記録するために、これらのピリオド列のみを使用しています。 現在のデータを保存する主なテーブルは、 現在のテーブル、または 時間テーブルと呼ばれます。

テンポラル テーブルには、これらの期間列に加え、ミラー化されたスキーマを使用する別のテーブル ("履歴テーブル" という) への参照も含まれています。 システムでは履歴テーブルを使用して、テンポラル テーブルの行が更新または削除されるたびに、行の以前のバージョンを自動的に格納します。 テンポラル テーブルの作成時に、既存の履歴テーブルを指定するか (スキーマ準拠である必要がある)、システムに既定の履歴テーブルを作成させます。

なぜ時に関するのか?

実際のデータソースは動的であり、ビジネスの意思決定はしばしばアナリストがデータ進化から得た洞察に依存しています。 テンポラル テーブルの使用例は次のとおりです。

  • すべてのデータ変更の監査と、必要に応じてのデータの科学捜査の実行
  • 過去の任意の時刻におけるデータの状態を再構築する
  • 長期の傾向の計算
  • 意思決定支援アプリケーションのための緩やかに変化するディメンションの維持
  • 偶発的なデータ変更やアプリケーション エラーからの復旧

Temporal はどのように動作しますか?

テーブルのシステム バージョン管理は、現行テーブルと履歴テーブルの 1 組のテーブルとして実装されます。 これらの各テーブル内では、2つの追加の datetime2 列が各行の有効期間を定義しています。

  • 期間開始列: システムはこの列にその行の開始時刻を記録します。この列は通常 ValidFrom 列として示されます。

  • 期間終了列: システムにより、この行の終了時間が、通常は ValidTo 列である列に書き込まれます。

現在のテーブルには、各行の ''現在の値'' が含まれています。 履歴テーブルには、存在する場合は各行のそれぞれの以前の値 (''古いバージョン'') と、それが有効であった期間の開始時間と終了時間が含まれています。

テンポラル テーブルのしくみを示す図。

次のスクリプトは、従業員情報を含むシナリオを示しています。

CREATE TABLE dbo.Employee
(
    [EmployeeID] INT NOT NULL PRIMARY KEY CLUSTERED,
    [Name] NVARCHAR (100) NOT NULL,
    [Position] VARCHAR (100) NOT NULL,
    [Department] VARCHAR (100) NOT NULL,
    [Address] NVARCHAR (1024) NOT NULL,
    [AnnualSalary] DECIMAL (10, 2) NOT NULL,
    [ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START,
    [ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.EmployeeHistory));

詳細については、「システム バージョン管理されたテンポラル テーブルを作成する」を参照してください。

  • 挿入:システムは ValidFrom 列の値を、システムクロックに基づいて現在のトランザクション開始時刻(UTC時区内)に設定し、 ValidTo 列の値を最大値 9999-12-31に割り当てます。 これは行をオープンとマークします。

  • 更新:システムは行の前の値を履歴テーブルに保存し、 ValidTo 列の値を現在のトランザクション開始時刻(UTCタイムゾーン)に設定します。これはシステムクロックに基づいています。 これは行をクローズドとマークし、行が有効であった期間が記録されます。 現行テーブルでは、行は新しい値で更新され、システムにより ValidFrom 列には、システム クロックに基づくトランザクションの開始時間 (UTC タイム ゾーン) の値が設定されます。 現行テーブル内の ValidTo 列の更新された行の値は、最大値の 9999-12-31 のままです。

  • 削除:システムは行の前の値を履歴テーブルに保存し、 ValidTo 列の値はシステムクロックに基づいて現在のトランザクション開始時刻(UTCタイムゾーン)に設定されます。 これは行をクローズドとマークし、前の行が有効であった期間が記録されます。 現行テーブルでは、その行は削除されます。 現在のテーブルのクエリではこの行は返されません。 履歴データを処理するクエリのみで、クローズドの行のデータが返されます。

  • マージ:操作は、MERGE文で指定されているアクションに応じて、最大3つの文(INSERTUPDATEDELETE)を実行するかのように振る舞います。

システムの datetime2 列に記録されている時間は、トランザクション自体の開始時間に基づいています。 たとえば、1 つのトランザクションで挿入されたすべての行の、SYSTEM_TIME 期間の開始に対応する列の UTC 時間は同じになります。

テンポラル テーブルに対してデータ変更クエリを実行すると、列の値が変更されなくても、履歴テーブルにデータベース エンジンが行を追加します。

テンポラル データのクエリ方法

SELECT ... FROM <table> ステートメントには新しい句 FOR SYSTEM_TIME があり、現在および履歴テーブル全体のデータに対してクエリを実行するための 5 つのテンポラル専用のサブ句があります。 この新しい SELECT ステートメントの構文は、1 つのテーブルで直接サポートされており、複数の結合を介して、また複数のテンポラル テーブル上のビューを介して反映されます。

クエリで5つのサブ節のいずれかで FOR SYSTEM_TIME 節を使用すると、結果には以下の画像のように時間テーブルからの 過去 データが含まれます。

時間クエリの動作を示す図。

次のクエリでは、少なくとも 2021 年 1 月 1 日から 2022 年 1 月 1 日 (上限の境界を含む) の間にアクティブであった、フィルター条件 WHERE EmployeeID = 1000 の従業員の行バージョンが検索されます。

SELECT *
FROM Employee FOR SYSTEM_TIME
    BETWEEN '2021-01-01 00:00:00.0000000' AND '2022-01-01 00:00:00.0000000'
WHERE EmployeeID = 1000
ORDER BY ValidFrom;

FOR SYSTEM_TIME では、有効期間がゼロの行 (ValidFrom = ValidTo) は除外されます。

データベース エンジンは、同じトランザクション内で同じプライマリキーに対して複数の更新を行うと、その行を生成します。 その場合、テンポラル クエリでは、トランザクション前の行バージョンと、トランザクション後の現在の行のみを返します。

それらの行を分析に含める必要がある場合は、履歴テーブルを直接クエリします。

以下の表では、該当行列の ValidFrom はクエリ対象のテーブルの ValidFrom 列の値を示し、ValidTo はクエリ対象のテーブルの ValidTo 列の値を示します。 完全な構文と例については、「FROM 句と JOIN、APPLY、PIVOT」および「システム バージョン管理されたテンポラル テーブル内のデータに対してクエリを実行する」を参照してください。

Expression 適格行 Note
AS OF date_time ValidFrom <= date_timeAND ValidTo >date_time 過去の指定された時点では現在であった値を含む行のあるテーブルを返します。 内部的には、テンポラル テーブルとその履歴テーブルの結合が行われます。 結果がフィルター処理されて、date_time パラメーターで指定された時点で有効だった行の値が返されます。 system_start_time_column_name 値が date_time パラメーター値と等しいかそれよりも小さく、system_end_time_column_name 値が date_time パラメーター値より大きい場合に、行の値は有効と見なされます。
FROM start_date_timeTOend_date_time ValidFrom < end_date_timeAND ValidTo >start_date_time 指定された時間範囲内でアクティブだったすべての行バージョンの値を含むテーブルを返します。 引数の FROM パラメーター値の前にアクティブになったか、 引数の TO パラメーター値の後にアクティブでなくなったかは関係ありません。 内部的には、テンポラル テーブルとその履歴テーブルの結合が行われます。 結果をフィルター処理すると、指定した時間範囲の中にいつでもにアクティブだったすべての行のバージョンの値を返します。 FROM エンドポイントによって定義されている下限のちょうど境界上でアクティブではなくなった行は含まれず、TO エンドポイントによって定義された上限のちょうど境界上でアクティブになったレコードも含まれません。
BETWEEN start_date_timeANDend_date_time ValidFrom <= end_date_timeAND ValidTo >start_date_time 返される行の表に、FOR SYSTEM_TIME FROM エンドポイントで定義された上限境界でアクティブになった行が含まれる点を除き、前述の TOend_date_time の説明と同じです。
CONTAINED IN (start_date_timeend_date_time) ValidFrom >= start_date_timeAND ValidTo <=end_date_time CONTAINED IN 引数の 2 つの期間値で定義された指定時間範囲内に開かれて閉じられたすべての行バージョンの値を含むテーブルを返します。 下限境界ちょうどで有効になった行、または上限境界ちょうどで有効でなくなった行は含まれます。
ALL すべての行 現行および履歴テーブルに属する行の和を返します。

期間列を非表示にする

ピリオド列を隠すことができるので、明示的に参照しないクエリ SELECT これらのカラム(例えば SELECT * FROM <table>)を返しません。

非表示の列を返すには、クエリで非表示の列を明示的に参照する必要があります。 同様に、INSERT および BULK INSERT ステートメントでも、これらの新しい期間列が存在しないかのように続行されます (列値は自動入力されます)。

HIDDEN句の使用方法の詳細については、CREATE TABLEALTER TABLEに関するページを参照してください。

Samples