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.