DB2 Version 10.1 for Linux, UNIX, and Windows

システム期間テンポラル表のデータの更新

システム期間テンポラル表のデータを更新すると、その結果として、それに関連付けられている履歴表に行が追加されます。

このタスクについて

システム期間テンポラル表の行の指定列の値を更新することに加えて、UPDATE ステートメントは既存の行のコピーをそれに関連付けられている履歴表に挿入します。 履歴行は、行を更新する同じトランザクションの一部として生成されます。 単一トランザクションが同じ行に複数の更新を行った場合、生成される履歴行は 1 つだけで、その行にはそのトランザクションによって変更される前のレコードの状態が反映されます。
注: 複数のトランザクションが同じ行を更新していると、タイム・スタンプ値の矛盾が起こることがあります。 このような矛盾が生じた場合、タイム・スタンプ調整が行われるか、あるいはトランザクションが失敗するかは、systime_period_adjデータベース構成パラメーターの設定によって決まります。 『その他の例』のセクションにある『異なるトランザクションによる行に対する複数の変更』の例で、詳しく説明します。 アプリケーション・プログラマーは、SQLCODE や SQLSTATE の値を使用して、SQL ステートメントから返される可能性のあるタイム・スタンプ値調整関連の戻りコードを処理できます。

手順

システム期間テンポラル表のデータを更新するには、UPDATE ステートメントを使用します。 例えば、顧客の保険補償範囲レベルにいくつかの誤りがあったことが分かり、システム期間テンポラル表へのデータの挿入のトピックでデータを追加した例示表の以下のデータが 2011 年 2 月 28 日に更新されたとします。
次の表には、policy_info 表の元のデータがあります。
表 1. システム期間テンポラル表の元のデータ (policy_info)
policy_id coverage sys_start sys_end ts_id
A123 12000 2010-01-31-
22.31.33.
495925000000
9999-12-30-
00.00.00.
000000000000
2010-01-31-
22.31.33.
495925000000
B345 18000 2010-01-31-
22.31.33.
495925000000
9999-12-30-
00.00.00.
000000000000
2010-01-31-
22.31.33.
495925000000
C567 20000 2010-01-31-
22.31.33.
495925000000
9999-12-30-
00.00.00.
000000000000
2010-01-31-
22.31.33.
495925000000

その他の例

このセクションでは、システム期間テンポラル表の他の更新例を示します。
時間指定
以下の例では、時間枠が表の更新の一部として指定されています。 以下の更新は、前述の「手順」セクションの更新後に実行されます。
UPDATE (SELECT * FROM policy_info
   FOR SYSTEM_TIME AS OF '2010-01-31-22.31.33.495925000000')
   SET coverage = coverage + 1000; 
この更新では、履歴行の更新を暗黙的に試行するので、エラーが返されます。 SELECT は policy_info 表を明示的に照会し、それに関連付けられた履歴表 (hist_policy_info) を暗黙的に照会しています。 hist_policy_info の C567 行が SELECT によって返されますが、暗黙的にアクセスされた履歴表の行は更新できません。
異なるトランザクションによる行に対する複数の変更
以下の例では、2 つのトランザクションが policy_info 表に対して同時に SQL ステートメントを実行しています。 この例では、タイム・スタンプが単純化されており、サンプル・システム・クロック値の代わりにプレースホルダーになっています。 例えば、この例では 2010-01-31-22.31.33.495925000000 の代わりに T1 が使用されています。 プレースホルダーの数値が高ければ高いほど、それはトランザクション内の後のアクションであることを示します。 例えば、T5 は T4 より後のアクションです。

単一の SQL トランザクションの中で複数の行を挿入または更新する場合、行開始列の値は、影響を受けるすべての行で同じになります。 その値は、トランザクションの最初のデータ変更ステートメントの実行時にシステム・クロックを読み取ることによって取得されます。 例えば、トランザクション ABC に関連付けられている時刻はすべて T1 になります。

トランザクション ABC トランザクション XYZ
T1: INSERT INTO policy_info
         (policy_id, coverage)
         VALUES ('S777',7000);
 
 
T2: INSERT INTO policy_info
         (policy_id, coverage)
         VALUES ('T888',8000);
T3: COMMIT;
T4: UPDATE policy_info
      SET policy_id = 'X999'
      WHERE policy_id = 'T888';
T5: INSERT INTO policy_info
         (policy_id, coverage)
         VALUES ('Y555',9000);
T6: COMMIT;
 
T1 および T2 で挿入を行った後、policy_info 表は以下のようになり、履歴表は空になります (hist_policy_info)。 sys_end 列の値 max に TIMESTAMP(12) データ・タイプの最大デフォルト値が取り込まれます。
表 4. policy_info table に対する異なるトランザクション挿入
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 max T1
T888 8000 T2 max T2
時刻 T4 のトランザクション ABC による更新の後、ポリシー情報は以下の表のようになります。 policy_info 表の行はすべて、トランザクション ABC の挿入アクティビティーおよび更新アクティビティーを反映します。 それらの行の sys_start 列と ts_id 列には時刻 T1 が取り込まれます。 これはトランザクション ABC の最初のデータ変更ステートメントの時刻です。 トランザクション XYZ によって挿入されたポリシー情報が更新され、元の行が履歴表に移動されます。
表 5. policy_info table に対する更新後の異なるトランザクション
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 max T1
X999 8000 T1 max T1
表 6. 異なるトランザクション更新後の履歴表 (hist_policy_info)
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T1 T2
履歴表の sys_end の時刻は、sys_start より前の時刻になっています。 この場合、時刻 T4 での更新は実行できず、トランザクション ABC は失敗します (SQLSTATE 57062、SQLCODE SQL20528N)。 このような失敗を避けるために、systime_period_adj データベース構成パラメーターを YES に設定することができます。この設定にすると、データベース・マネージャーが行開始タイム・スタンプを調整できるようになります (SQLSTATE 01695、SQLCODE SQL5191W)。 トランザクション ABC の時刻 T4 の更新の sys_start タイム・スタンプは、時刻 T2 + 差分 (T2+delta) に設定されます。 この調整は、時刻 T4 の更新にのみ適用されます。トランザクション ABC によって行われるそれ以外の変更はすべて、引き続き時刻 T1 タイム・スタンプを使用します (例えば、policy_id Y555 を持つポリシーの挿入)。 この調整とトランザクション ABC の実行の後、保険ポリシー表の中のデータは次のようになります。
表 7. 時刻調整後の異なるトランザクション (policy_info)
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 max T1
X999 8000 T2+delta max T1
Y555 9000 T1 max T1
表 8. 時刻調整後の履歴表 (hist_policy_info)
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T2+delta T2
同じトランザクションで行われる、行に対する複数の変更
以下の例のトランザクションは、1 つの行に対して複数の変更を行います。 前例の保険ポリシー表を使用して、トランザクション ABC を引き続き使用しますが、時刻 T6 に policy_id X999 を使ってポリシーを更新します (最初、T6 は COMMIT ステートメントでした)。
トランザクション ABC
T6: UPDATE policy_info SET policy_id = 'R111' WHERE policy_id = 'X999';
T7: COMMIT;
この時点で、この行には以下の変更が加えられています。
  1. 時刻 T2 にトランザクション XYZ によってポリシー T888 が作成される。
  2. 時刻 T4 にトランザクション ABC によってポリシー X999 に更新される。
  3. 時刻 T6 にトランザクション ABC によってポリシー R111 に更新される。
1 つのトランザクションが同じ行に対して複数の更新を行う場合、データベース・マネージャーは最初の変更の履歴行のみを生成します。 この結果、以下の表のようになります。
表 9. 更新後の同じトランザクション (policy_info)
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 max T1
R111 8000 T1 max T1
Y555 9000 T1 max T1
表 10. 同じトランザクション更新後の履歴表 (hist_policy_info)
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T2+delta T2
データベース・マネージャーはトランザクション開始 ID (ts_id) を使用して、行を変更するトランザクションを一意的に識別します。 単一 SQL トランザクション内で複数の行が挿入または更新される場合、トランザクション開始 ID 列の値は、すべての行について同じであり、他のトランザクションでその列に対して生成される値とは異なる固有の値になります。 履歴行を生成する前に、データベース・マネージャーは、行に対する最後の更新が、時刻 T1 (ts_id は T1) に開始したトランザクションに対するものであったことを確認します。この時刻は、現行の変更を行うトランザクションと同じトランザクション開始時刻であるため、履歴行は生成されません。 policy_info 表の行の sys_start 値は時刻 T1 に変更されます。
ビューの更新
システム期間テンポラル表またはバイテンポラル表を参照するビューを更新できるのは、ビュー定義に FOR SYSTEM_TIME 節が含まれていない場合のみです。 以下の UPDATE ステートメントは policy_info 表を更新し、履歴行を生成します。
CREATE VIEW viewA AS SELECT * FROM policy_info;
UPDATE viewA SET col2 = col2 + 1000;
システム期間テンポラル表またはバイテンポラル表を参照するビューのビュー定義に FOR SYSTEM_TIME 節が含まれる場合、INSTEAD OF トリガーを定義することによってそのビューを更新可能にすることができます。 以下の例は、regular_table 表を更新します。
CREATE VIEW viewB AS SELECT * FROM policy_info;
   FOR SYSTEM_TIME BETWEEN 
   TIMESTAMP '2010-01-01 10:00:00' AND TIMESTAMP '2011-01-01 10:00:00';

CREATE TRIGGER update INSTEAD OF UPDATE ON viewB
   REFERENCING NEW AS n FOR EACH ROW
   UPDATE regular_table SET col1 = n.id;

UPDATE viewB set id = 500;