Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle-Trigger nach dem Einfügen oder Löschen

Worauf Sie gestoßen sind, ist die klassische „Mutating Table“-Ausnahme. In einem ROW-Trigger erlaubt Ihnen Oracle nicht, eine Abfrage für die Tabelle auszuführen, für die der Trigger definiert ist - also ist es der SELECT gegen TABELLE1 im DELETING Teil des Auslösers, der dieses Problem verursacht.

Es gibt ein paar Möglichkeiten, dies zu umgehen. In dieser Situation ist es vielleicht am besten, einen zusammengesetzten Trigger zu verwenden, der etwa so aussehen würde:

CREATE OR REPLACE TRIGGER TABLE1_NUM_TRG
  FOR INSERT OR DELETE ON TABLE1
COMPOUND TRIGGER
  TYPE NUMBER_TABLE IS TABLE OF NUMBER;
  tblTABLE2_IDS  NUMBER_TABLE;

  BEFORE STATEMENT IS
  BEGIN
    tblTABLE2_IDS := NUMBER_TABLE();
  END BEFORE STATEMENT;

  AFTER EACH ROW IS
  BEGIN
    IF INSERTING THEN
      UPDATE TABLE2 t2
        SET    t2.TABLE2NUM = :new.NUM
        WHERE  t2.ID = :new.TABLE2_ID;
    ELSIF DELETING THEN
      tblTABLE2_IDS.EXTEND;
      tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.TABLE2_ID;
    END IF;
  END AFTER EACH ROW;

  AFTER STATEMENT IS
  BEGIN
    IF tblTABLE2_IDS.COUNT > 0 THEN
      FOR i IN tblTABLE2_IDS.FIRST..tblTABLE2_IDS.LAST LOOP
        UPDATE TABLE2 t2
          SET t2.TABLE2NUM = (SELECT NUM
                                FROM (SELECT t1.NUM
                                        FROM TABLE1 t1
                                        WHERE t1.TABLE2_ID = tblTABLE2_IDS(i) 
                                        ORDER BY modification_date DESC)
                                WHERE ROWNUM = 1)
          WHERE t2.ID = tblTABLE2_IDS(i);
      END LOOP;
    END IF;
  END AFTER STATEMENT;
END TABLE1_NUM_TRG;

Ein zusammengesetzter Trigger lässt jeden Zeitpunkt (BEFORE STATEMENT , BEFORE ROW , AFTER ROW , und AFTER STATEMENT ) zu behandeln. Beachten Sie, dass die Zeitpunkte immer in der angegebenen Reihenfolge aufgerufen werden. Wenn eine entsprechende SQL-Anweisung (d. h. INSERT INTO TABLE1 oder DELETE FROM TABLE1 ) ausgeführt und dieser Trigger ausgelöst wird, ist der erste aufzurufende Zeitpunkt BEFORE STATEMENT , und den Code im BEFORE STATEMENT Handler weist eine PL/SQL-Tabelle zu, um eine Reihe von Zahlen zu speichern. In diesem Fall sind die in der PL/SQL-Tabelle zu speichernden Zahlen die TABLE2_ID-Werte von TABLE1. (Eine PL/SQL-Tabelle wird beispielsweise anstelle eines Arrays verwendet, da eine Tabelle eine unterschiedliche Anzahl von Werten enthalten kann, während wir bei Verwendung eines Arrays im Voraus wissen müssten, wie viele Zahlen wir speichern müssten. Wir können nicht im Voraus wissen, wie viele Zeilen von einer bestimmten Anweisung betroffen sind, also verwenden wir eine PL/SQL-Tabelle).

Wenn der AFTER EACH ROW Zeitpunkt erreicht ist und wir feststellen, dass die verarbeitete Anweisung ein INSERT ist, geht der Trigger einfach weiter und führt das notwendige UPDATE für TABLE2 durch, da dies kein Problem verursacht. Wenn jedoch ein DELETE ausgeführt wird, speichert der Trigger die TABLE1.TABLE2_ID in der zuvor zugeordneten PL/SQL-Tabelle. Wenn die AFTER STATEMENT Ist der Zeitpunkt schließlich erreicht, wird die zuvor zugeordnete PL/SQL-Tabelle durchlaufen und für jede gefundene TABLE2_ID das entsprechende Update durchgeführt.

Dokumentation hier.