'INSERT' in Trigger

Moin!
Ich versuche gerade mein weiter unten beschriebenes Problem zu
reduzieren.

Von vorne: Ich möchte eines bestimmtes Feld einer Tabelle
mit einem UPDATE-Trigger kontrollieren. D.h., wenn in dieses
Feld ein bestimmter Wert eingegeben wird, soll ein weiterer
Datensatz in die gleiche Tabelle eingefügt werden.

Das Problem dabei ist: Egal auf welche Art und Weise ich einen
Datensatz einfüge, immer bekomme ich den Fehler, dass die Tabelle
mutiert. Es klingt ja auch logisch.
Trotzdem muss es doch irgendeinen Weg geben, Oracle auszutricksen.

Bin für jeden Tip dankbar.

Jones

-)=

Wie wäre es mit Stored Procedure statt Trigger? Eine die alle Spalten in der Tabelle als Parameter nimmt, diese Prüfung vornimmt und dann ein oder zwei Datensätze einfügt.

Grüße, Robert

Hi Jones,

wenn du bei einem BEFORE … FOR EACH ROW-Trigger die Tabelle,
für die der Trigger definiert ist, manipulieren willst, dann
geht das natürlich nicht: Stell dir vor, du machst ein UPDATE
mit einer WHERE-clause, die das Attribut beinhaltet, das du im
Trigger manipulierst. Das Ergebnis wäre dann gfs. davon
abhängig, in welcher Reihenfolge Oracle die Tupel beim Update
behandelt. So eine Situation nennt man „mutating table“.

Zweitens: Wenn du z.B. in einem INSERT-Trigger einen INSERT
machen willst, geht das auch nicht, da dann der Trigger rekursiv
feuert. Typische Fehlermeldung: „Maximale Anzahl offener Cursor
überschritten“

Wenn, wie in deinem Fall, ein UPDATE ein INSERT nach sich ziehen
soll, dann geht das mit folgendem Trick:
Der BEFORE UPDATE … FOR EACH ROW-Trigger sammelt in einer
PL/SQL-Table alle Daten auf, die anschließend mit einem
AFTER UPDATE … -Trigger in die Relation eingetragen werden.
Um eine PL/SQL-Tabelle zu haben, muss man ein PACKAGE anlegen.

Beispiel: Bei jedem UPDATE: Wenn subid = 0, dann wird ein
zusätzlicher Datensatz angelegt, jedoch mit subid + 1.

DROP TABLE test;
CREATE TABLE test (
 id INTEGER,
 subid INTEGER,
 data INTEGER
);


CREATE OR REPLACE PACKAGE test\_data AS
 TYPE type\_test IS TABLE OF test%ROWTYPE INDEX BY BINARY\_INTEGER;

 table\_test type\_test;
 v\_NumEntries BINARY\_INTEGER := 0;
END test\_data;
/


CREATE OR REPLACE TRIGGER test\_bur
 BEFORE UPDATE ON test FOR EACH ROW
BEGIN
 IF :new.subid = 0 THEN
 -- wir merken uns im package: :new.id, :new.subid + 1, :new.data
 test\_data.v\_NumEntries := test\_data.v\_NumEntries + 1;
 test\_data.table\_test(test\_data.v\_NumEntries).id := :new.id;
 test\_data.table\_test(test\_data.v\_NumEntries).subid := :new.subid + 1;
 test\_data.table\_test(test\_data.v\_NumEntries).data := :new.data;
 END IF;
END;
/


CREATE OR REPLACE TRIGGER test\_au
 AFTER UPDATE ON test
BEGIN
 -- jetzt iterieren wir über die tables und machen INSERT INTO test...
 FOR v\_loop IN 1 .. test\_data.v\_NumEntries LOOP
 INSERT INTO test VALUES (
 test\_data.table\_test(v\_loop).id,
 test\_data.table\_test(v\_loop).subid,
 test\_data.table\_test(v\_loop).data);
 END LOOP;
 -- loop counter wieder zurücksetzen
 test\_data.v\_NumEntries := 0;
END;
/


INSERT INTO test VALUES (1,2,3);
UPDATE test SET subid = 0;
SELECT \* FROM test;


 ID SUBID DATA
--------- --------- ---------
 1 0 3
 1 1 3

ciao, Bernhard