Aktualisieren von Daten in einer temporalen Tabelle für Systemzeitraum

Das Aktualisieren von Daten in einer temporalen Tabelle für Systemzeitraum führt dazu, dass Zeilen in die zugehörige Protokolltabelle eingefügt werden.

Informationen zu dieser Task

Zusätzlich zur Aktualisierung von Werten angegebener Spalten in den Zeilen der temporalen Tabelle für Systemzeitraum fügt die Anweisung UPDATE eine Kopie der vorhandenen Zeile in die zugehörige Protokolltabelle ein. Die Protokollzeile wird im Rahmen der Transaktion generiert, die auch die Zeile aktualisiert. Wenn eine einzelne Transaktion mehrere Aktualisierungen derselben Zeile vornimmt, wird nur eine Verlaufszeile generiert, die den Status des Datensatzes vor der Änderung durch die Transaktion widerspiegelt.
Hinweis: Zeitmarkenwertkonflikte können auftreten, wenn mehrere Transaktionen dieselbe Zeile aktualisieren. Wenn diese Konflikte auftreten, bestimmt die Einstellung für den Datenbankkonfigurationsparameter systime_period_adj , ob Zeitmarkenanpassungen vorgenommen werden oder ob Transaktionen fehlschlagen. Das Beispiel Mehrere Änderungen an einer Zeile durch unterschiedliche Transaktionen im Abschnitt Weitere Beispiele bietet weitere Details. Anwendungsprogrammierer sollten die Verwendung von SQLCODE- oder SQLSTATE-Werten erwägen, um potenzielle auf die Anpassung von Zeitmarkenwerten bezogene Rückkehrcodes über SQL-Anweisungen zu handhaben.

Prozedur

Zum Aktualisieren von Daten in einer temporalen Tabelle für Systemzeitraum wird die Anweisung UPDATE verwendet.
Zum Beispiel wurde festgestellt, dass es einige Fehler in den Versicherungsdeckungssummen für einen Kunden gab, und die folgenden Daten wurden am 28. Februar 2011 (2011-02-28) in der Beispieltabelle aktualisiert, die Daten im Einfügen von Daten in eine System-Perioden-Zeittafel -Thema hinzugefügt hatte.
Die folgende Tabelle enthält die ursprünglichen Daten der Tabelle policy_info.
Tabelle 1. Ursprüngliche Daten in der temporalen Tabelle für Systemzeitraum (policy_info)
policy_id coverage sys_start sys_end ts_id
A123 12000 31.01.2010-
22.31.33.
495925000000
9999-12-30-

00.00.00.000000000000
31.01.2010-
22.31.33.
495925000000
B345 18000 31.01.2010-
22.31.33.
495925000000
9999-12-30-

00.00.00.000000000000
31.01.2010-
22.31.33.
495925000000
C567 20000 31.01.2010-
22.31.33.
495925000000
9999-12-30-

00.00.00.000000000000
31.01.2010-
22.31.33.
495925000000
  • Die Deckung (coverage) für die Police C567 soll 25000 betragen.
    UPDATE policy_info
       SET coverage = 25000
       WHERE policy_id = 'C567';
    
    Die Aktualisierung der Police C567 hat Auswirkungen auf die temporale Tabelle für Systemzeitraum sowie die zugehörige Protokolltabelle und führt dazu, dass die folgenden Aktionen ausgeführt werden:
    1. Der Deckungswert für die Zeile mit der Police C567 wird auf 25000 aktualisiert.
    2. In der temporalen Tabelle für Systemzeitraum aktualisiert der Datenbankmanager die Werte von sys_start und ts_id auf das Datum der Aktualisierung.
    3. Die ursprüngliche Zeile wird in die Protokolltabelle versetzt. Der Datenbankmanager aktualisiert den Wert für sys_end auf das Datum der Aktualisierung. Diese Zeile kann als gültige Deckung für die Police C567 von 2010-01-31-22.31.33.495925000000 bis 2011-02-28-09.10.12.649592000000 interpretiert werden.
    Tabelle 2. Aktualisierte Daten in der temporalen Tabelle für Systemzeitraum (policy_info)
    policy_id coverage sys_start sys_end ts_id
    A123 12000 31.01.2010-
    22.31.33.
    495925000000
    9999-12-30-

    00.00.00.000000000000
    31.01.2010-
    22.31.33.
    495925000000
    B345 18000 31.01.2010-
    22.31.33.
    495925000000
    9999-12-30-

    00.00.00.000000000000
    31.01.2010-
    22.31.33.
    495925000000
    C567 25000 28.02.2011-
    09.10.12.
    649592000000
    9999-12-30-

    00.00.00.000000000000
    28.02.2011-
    09.10.12.
    649592000000
    Tabelle 3. Protokolltabelle (hist_policy_info) nach Aktualisierung
    policy_id coverage sys_start sys_end ts_id
    C567 20000 31.01.2010-
    22.31.33.
    495925000000
    28.02.2011-
    09.10.12.
    649592000000
    31.01.2010-
    22.31.33.
    495925000000

Weitere Beispiele

Der folgende Abschnitt enthält weitere Beispiele zur Aktualisierung von temporalen Tabellen für Systemzeitraum.
Zeitangaben
Im folgenden Beispiel wird im Rahmen der Tabellenaktualisierung ein Zeitraum angegeben. Die folgende Aktualisierung wird nach der im Abschnitt Vorgehensweise beschriebenen Aktualisierung ausgeführt.
UPDATE (SELECT * FROM policy_info
   FOR SYSTEM_TIME AS OF '2010-01-31-22.31.33.495925000000')
   SET coverage = coverage + 1000; 
Diese Aktualisierung gibt einen Fehler zurück, da implizit versucht wird, Protokollzeilen zu aktualisieren. Die Anweisung SELECT fragt explizit die Tabelle policy_info und implizit die zugehörige Protokolltabelle ab (hist_policy_info). Die Zeile C567 in hist_policy_info würde von SELECT zurückgegeben, aber Zeilen in einer Protokolltabelle, auf die implizit zugegriffen wurde, können nicht aktualisiert werden.
Mehrere Änderungen an einer Zeile durch unterschiedliche Transaktionen
Im folgenden Beispiel führen zwei Transaktionen gleichzeitig SQL-Anweisungen für die Tabelle policy_info aus. In diesem Beispiel werden die Zeitmarken der Einfachheit halber durch einen Platzhalter und nicht durch einen Systemuhrwert angegeben. Beispielsweise wird anstelle von 2010-01-31-22.31.33.495925000000 der Platzhalter T1 verwendet. Platzhalter mit einer höheren Nummerierung weisen auf nachfolgende Aktionen innerhalb der Transaktion hin. T5 ist zum Beispiel ein späterer Zeitpunkt als T4.

Beim Einfügen oder Aktualisieren mehrerer Zeilen innerhalb einer einzelnen SQL-Transaktion sind die Werte für die Zeilenbeginnspalten für alle betroffenen Zeilen identisch. Dieser Wert stammt aus dem Ablesen der Systemuhr zu dem Zeitpunkt, an dem die erste Datenänderungsanweisung in der Transaktion ausgeführt wird. Zum Beispiel verfügen alle der Transaktion ABC zugeordneten Zeiten über den Zeitwert T1.

Transaktion ABC Transaktion 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;
 
Nach den Einfügungen in T1 und T2würde die Tabelle policy_info wie folgt aussehen und die Protokolltabelle wäre leer (hist_policy_info). Der Wert max in der Spalte sys_end wird mit dem maximalen Standardwert für den Datentyp TIMESTAMP (12) gefüllt.
Tabelle 4. Einfügungen unterschiedlicher Transaktionen in die Tabelle 'policy_info'
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 Max. T1
T888 8000 T2 Max. T2
Nach der Aktualisierung durch die Transaktion ABC zum Zeitpunkt T4 entsprechen die Policeninformationen den Daten in den folgenden Tabellen. Alle Zeilen in der Tabelle policy_info geben die Einfügungs- und Aktualisierungsaktivitäten von Transaktion ABC wieder. Die Spalten sys_start und ts_id für diese Zeilen werden mit dem Zeitwert von T1 gefüllt, der den Zeitpunkt der ersten Datenänderungsanweisung in der Transaktion ABC angibt. Die von der Transaktion XYZ eingefügten Policeninformationen wurden aktualisiert und die ursprüngliche Zeile wird in die Protokolltabelle versetzt.
Tabelle 5. Unterschiedliche Transaktionen nach Aktualisierung der Tabelle 'policy_info'
policy_id coverage sys_start sys_end ts_id
S777 7000 T1 Max. T1
X999 8000 T1 Max. T1
Tabelle 6: Protokolltabelle nach Aktualisierung durch unterschiedliche Transaktionen
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T1 T2
Die Protokolltabelle enthält einen Wert für sys_end, der vor dem Wert von sys_start liegt. In dieser Situation könnte die Aktualisierung zum Zeitpunkt T4 nicht ausgeführt werden und die Transaktion ABC würde fehlschlagen (SQLSTATE 57062, SQLCODE SQL20528N). Zum Vermeiden solcher Fehler kann der Datenbankkonfigurationsparameter systime_period_adj auf den Wert YES gesetzt werden, wodurch es dem Datenbankmanager möglich ist, die Zeitmarke der Beginnspalte für Zeile anzupassen (SQLSTATE 01695, SQLCODE SQL5191W). Die Zeitmarke sys_start für die Aktualisierung zum Zeitpunkt T4 in Transaktion ABC wird auf den Zeitpunkt T2 zuzüglich eines Deltas (T2+delta) gesetzt. Die Anpassung bezieht sich nur auf die Aktualisierung zum Zeitpunkt T4; alle anderen von der Transaktion ABC durchgeführten Änderungen verwenden weiterhin die Zeitmarke für den Zeitpunkt T1 (z. B. die Einfügung der Police mit policy_id Y555). Nach dieser Anpassung und der Ausführung der Transaktion ABC enthalten die Tabellen für Versicherungspolicen die folgenden Daten:
Tabelle 7: Unterschiedliche Transaktionen nach Zeitanpassung (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
Tabelle 8. Protokolltabelle nach Zeitanpassung (hist_policy_info)
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T2+delta T2
Mehrere Änderungen an einer Zeile innerhalb einer Transaktion
Im folgenden Beispiel nimmt eine Transaktion mehrere Änderungen an einer Zeile vor: Unter Verwendung der Tabellen für Versicherungspolicen aus dem vorherigen Beispiel fährt die Transaktion ABS fort und aktualisiert die Police mit policy_id X999 zum Zeitpunkt T6 (T6 war ursprünglich eine Anweisung COMMIT).
Transaktion ABC
T6: UPDATE policy_info SET policy_id = 'R111' WHERE policy_id = 'X999';
T7: COMMIT;
Diese Zeile wurde nun wie folgt geändert:
  1. Erstellt als Richtlinie T888 von Transaktion XYZ zum Zeitpunkt T2.
  2. Aktualisiert als Richtlinie X999 von Transaktion ABC zum Zeitpunkt T4.
  3. Aktualisiert als Richtlinie R111 von Transaktion ABC zum Zeitpunkt T6.
Wenn eine Transaktion mehrere Aktualisierungen für dieselbe Zeile vornimmt, generiert der Datenbankmanager nur für die erste Änderung eine Protokollzeile. Dies führt als Ergebnis zu den folgenden Tabellen:
Tabelle 9. Dieselbe Transaktion nach Aktualisierung (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
Tabelle 10: Protokolltabelle nach Aktualisierung durch dieselbe Transaktion (hist_policy_info)
policy_id coverage sys_start sys_end ts_id
T888 8000 T2 T2+delta T2
Der Datenbankmanager verwendet die Transaktionsstart-ID (ts_id), um die für die Zeilenänderung verantwortliche Transaktion eindeutig zu identifizieren. Beim Einfügen oder Aktualisieren mehrerer Zeilen innerhalb einer einzelnen SQL-Transaktion sind die Werte der Spalte für die Transaktionsstart-ID für alle Zeilen identisch und unterscheiden sich von den Werten, die von anderen Transaktionen für diese Spalte generiert wurden. Vor der Generierung einer Protokollzeile stellt der Datenbankmanager fest, dass sich die letzte Aktualisierung der Zeile auf die Transaktion bezieht, die zum Zeitpunkt T1 (ts_id ist T1) gestartet wurde; da dieser Wert der Transaktionsstartzeit für die Transaktion entspricht, die die aktuelle Änderung durchführt, wird keine Protokollzeile generiert. Der sys_start-Wert für die Zeile in der Tabelle policy_info wird in den Zeitpunkt T1 geändert.
Aktualisieren einer Sicht
Eine Sicht, die auf eine temporale Tabelle für Systemzeitraum oder eine bitemporale Tabelle verweist, kann nur aktualisiert werden, wenn die Sichtdefinition nicht die Klausel FOR SYSTEM_TIME enthält. Die folgende Anweisung UPDATE aktualisiert die Tabelle policy_info und generiert Protokollzeilen.
CREATE VIEW viewA AS SELECT * FROM policy_info;
UPDATE viewA SET col2 = col2 + 1000;
Eine Sicht, die auf eine temporale Tabelle für Systemzeitraum oder eine bitemporale Tabelle mit einer Sichtdefinition verweist, die die Klausel FOR SYSTEM_TIME enthält, kann durch Definieren eines Triggers INSTEAD OF aktualisierbar gemacht werden. Das folgende Beispiel aktualisiert die Tabelle 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;