Oracle - Trigger erstellen Sie eine Geschichte auf Zeile aktualisieren

Ersten, wir haben derzeit das Verhalten, das gewünscht ist, aber es ist nicht trivial zu erhalten, wenn änderungen an der Datenbank erforderlich sind. Ich bin auf der Suche nach etwas einfacher, effizienter oder einfacher zu pflegen (alles, was nicht jeder von denen 3 wäre sehr willkommen). Wenn wir ein update durchzuführen, eine Geschichte Zeile angelegt, die eine Kopie der aktuellen Zeile, und die aktuelle Zeile die Werte dann aktualisiert. Das Ergebnis ist, dass wir eine Geschichte aufnehmen, wie die Reihe war, bevor es aktualisiert wurde.

Argumentation: Wir haben die Kompatibilität mit einer Reihe von Bundes-Regeln, und ging diesen Weg, um eine vollständige audit-Historie der alles, so gut wie wir können sich an der Datenbank an einem beliebigen Punkt in der Zeit und sehen, wie die Dinge sah (für zukünftige Anforderungen). Aus ähnlichen Gründen, die ich nicht ändern kann, wie Geschichte aufgenommen wird...irgendeine Lösung müssen die gleichen Daten wie die aktuelle Trigger erstellen.

Hier ist, was der aktuelle Auslöser Aussehen für die Contact Tabelle:

(stripped nutzlos Felder für die Kürze, die Anzahl der Felder spielt keine Rolle)

Bevor update (jede Zeile):

DECLARE
     indexnb number;
BEGIN
  :new.date_modified := '31-DEC-9999';
  indexnb := STATE_PKG.newCONTACTRows.count + 1;
  :new.date_start := sysdate;
  :new.version := :old.version + 1;
  state_pkg.newCONTACTRows(indexnb).ID := :old.ID;
  state_pkg.newCONTACTRows(indexnb).PREFIX := :old.PREFIX;
  state_pkg.newCONTACTRows(indexnb).FIRST_NAME := :old.FIRST_NAME;
  state_pkg.newCONTACTRows(indexnb).MIDDLE_NAME := :old.MIDDLE_NAME;
  state_pkg.newCONTACTRows(indexnb).LAST_NAME := :old.LAST_NAME;
  --Audit columns after this
  state_pkg.newCONTACTRows(indexnb).OWNER := :old.OWNER;
  state_pkg.newCONTACTRows(indexnb).LAST_USER := :old.LAST_USER;
  state_pkg.newCONTACTRows(indexnb).DATE_CREATED := :old.DATE_CREATED;
  state_pkg.newCONTACTRows(indexnb).DATE_MODIFIED := sysdate;
  state_pkg.newCONTACTRows(indexnb).VERSION := :old.VERSION;
  state_pkg.newCONTACTRows(indexnb).ENTITY_ID := :old.id;
  state_pkg.newCONTACTRows(indexnb).RECORD_STATUS := :old.RECORD_STATUS;
  state_pkg.newCONTACTRows(indexnb).DATE_START := :old.DATE_START;
END;

Bevor update (einmal für alle Zeilen):

BEGIN
  state_pkg.newCONTACTRows := state_pkg.eCONTACTRows;
END;

Nach update (einmal für alle Zeilen):

DECLARE
BEGIN
  for i in 1 .. STATE_PKG.newCONTACTRows.COUNT loop
    INSERT INTO "CONTACT" (
      ID, 
      PREFIX, 
      FIRST_NAME, 
      MIDDLE_NAME, 
      LAST_NAME, 
      OWNER, 
      LAST_USER, 
      DATE_CREATED, 
      DATE_MODIFIED, 
      VERSION, 
      ENTITY_ID, 
      RECORD_STATUS, 
      DATE_START)
    VALUES (
      CONTACT_SEQ.NEXTVAL, 
      state_pkg.newCONTACTRows(i).PREFIX,
      state_pkg.newCONTACTRows(i).FIRST_NAME,
      state_pkg.newCONTACTRows(i).MIDDLE_NAME,
      state_pkg.newCONTACTRows(i).LAST_NAME,
      state_pkg.newCONTACTRows(i).OWNER,
      state_pkg.newCONTACTRows(i).LAST_USER,
      state_pkg.newCONTACTRows(i).DATE_CREATED,
      state_pkg.newCONTACTRows(i).DATE_MODIFIED,
      state_pkg.newCONTACTRows(i).VERSION,
      state_pkg.newCONTACTRows(i).ENTITY_ID,
      state_pkg.newCONTACTRows(i).RECORD_STATUS,
      state_pkg.newCONTACTRows(i).DATE_START
    );
  end loop;
END;

Paket definiert als (gekürzt, die volle version ist gerade Kopie dieses pro Tisch):

PACKAGE STATE_PKG IS
  TYPE CONTACTArray IS TABLE OF CONTACT%ROWTYPE INDEX BY BINARY_INTEGER; 
  newCONTACTRows CONTACTArray; 
  eCONTACTRows CONTACTArray;
END;

Das aktuelle Ergebnis

Hier ist eine resultierende Geschichte Beispiel:

ID    First Last   Ver  Entity_ID  Date_Start              Date_Modified  
1196  John  Smith  5    0          12/11/2009 10:20:11 PM  12/31/9999 12:00:00 AM
1201  John  Smith  0    1196       12/11/2009 09:35:20 PM  12/11/2009 10:16:49 PM
1203  John  Smith  1    1196       12/11/2009 10:16:49 PM  12/11/2009 10:17:07 PM
1205  John  Smith  2    1196       12/11/2009 10:17:07 PM  12/11/2009 10:17:19 PM
1207  John  Smith  3    1196       12/11/2009 10:17:19 PM  12/11/2009 10:20:00 PM
1209  John  Smith  4    1196       12/11/2009 10:20:00 PM  12/11/2009 10:20:11 PM

Jeder Geschichte-Eintrag hat eine Entity_ID das ist die ID der aktuellen Zeile, die Date_Start auf der neuen Platte entspricht der Date_Modified der letzten Geschichte Reihe. Dies erlaubt es uns, Anfragen wie Where Entity_ID = :id Or ID = :id And :myDate < Date_Modified And :myDate >= Date_Start. Die Geschichte kann abgerufen werden, indem Entity_ID = :current_id.

Ist es ein besserer Ansatz, der hoffentlich mehr wartbar/flexible, dies zu tun? Das Konzept ist einfach, wenn die Aktualisierung einer Zeile, kopieren Sie Sie auf die gleiche Tabelle über eine insert mit den alten Werten, dann aktualisieren Sie die aktuelle Zeile...aber eigentlich tut das, ich habe noch eine einfachere Möglichkeit. Ich hoffe jemand viel schwieriger/weiser in Oracle gibt es eine bessere Lösung für dieses. Geschwindigkeit spielt keine große Rolle, wir sind 99% liest 1% schreibt wie die meisten web-Anwendungen und alle bulk operations sind Einsätze, nicht die updates, das würde nicht jeder schaffen Geschichte.

Wenn jemand irgendwelche Ideen zur Vereinfachung der Wartung auf dieser, ich wäre sehr dankbar, danke!

  • Sorry, dass ich den Punkt verpasst das erste mal um. Ich habe neu geschrieben, meine Antwort auf eigentlich Ihr Problem.
InformationsquelleAutor Nick Craver | 2010-02-10
Schreibe einen Kommentar