it-swarm.com.de

Tabelle ändert sich, Trigger/Funktion wird möglicherweise nicht angezeigt

Hier ist das Problem:

Erstellen Sie einen Auslöser, der verhindert, dass Änderungen an der Einnahme-Beziehung vorgenommen werden, wodurch die durchschnittliche Gesamtnote in einer bestimmten Klasse unter 2,5 sinkt. Hinweis: Dieser Trigger ist nicht dazu gedacht, den durchschnittlichen GPA eines bestimmten Schülers anzusprechen, sondern sollte die Durchschnittsnote für alle in einer bestimmten Klasse zugewiesenen Noten betreffen.

Hier ist das Schema:

Student-schema =(studentnum, name, standing, gpa, major)
Class-schema = (schedulenum, semester, department, classnum, days, time, place, enrollment)
Instructor-schema = (name, department, office)
Teaches-schema = (name, schedulenum, semester)
Taking-schema = (studentnum, schedulenum, semester, grade)

Ich habe eine schreckliche Zeit mit diesen Auslösern, aber hier ist mein Versuch, dies zu erreichen:

CREATE OR REPLACE TRIGGER stopChange
    AFTER UPDATE OR INSERT OR DELETE ON taking
    REFERENCING OLD AS old
    NEW AS new
    FOR EACH ROW
DECLARE

grd_avg taking.grade%TYPE;

BEGIN
    SELECT AVG(grade)
    INTO grd_avg
    FROM taking
    WHERE studentnum = :new.studentnum
    AND schedulenum = :new.schedulenum
    AND semester = :new.semester;

    IF grd_avg < 2.5 THEN
        UPDATE taking
        SET grade = :old.grade
        WHERE studentnum = :old.studentnum
        AND schedulenum = :old.schedulenum
        AND semester = :old.semester;
    END IF;

END;   
/

Ich mache offensichtlich etwas falsch, denn wenn ich dann ein Tuple aktualisiere oder lösche, erhalte ich die Fehlermeldung:

ERROR at line 1:
ORA-04091: table TAKING is mutating, trigger/function may not see it
ORA-06512: at "STOPCHANGE", line 6
ORA-04088: error during execution of trigger 'STOPCHANGE'

Irgendein Rat? Ich benutze Oracle.

7
The Rationalist

Ich denke, Sie können dies beheben, indem Sie dies als vor auslösen und nicht als nach . Für Einfügungen und Löschungen kann dies jedoch etwas kompliziert sein. Die Idee ist:

CREATE OR REPLACE TRIGGER stopChange
    BEFORE UPDATE OR INSERT OR DELETE ON taking
    REFERENCING OLD AS old
    NEW AS new
    FOR EACH ROW
DECLARE

grd_avg taking.grade%TYPE;

BEGIN
    SELECT (SUM(grade) - oldgrade + new.grade) / count(*)
    INTO grd_avg
    FROM taking
    WHERE studentnum = :new.studentnum
    AND schedulenum = :new.schedulenum
    AND semester = :new.semester;

    IF grd_avg < 2.5 THEN
        new.grade = old.grade
    END IF;
END;  
4
Gordon Linoff

verwenden Sie diese Anweisung in DECLARE, wird es funktionieren.

pragma autonomous_transaction;
11
Sweta

Zuerst müssen Sie über Trigger, mutierende Tabellenfehler und zusammengesetzte Trigger lesen: http://docs.Oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

Ihr Auslöser ist NACH UPDATE OR INSERT OR DELETE. Bedeutet, wenn Sie die UPDATE OR INSERT OR DELETE-Anweisungen in dieser Tabelle ausführen, wird der Trigger ausgelöst. Sie versuchen jedoch, dieselbe Tabelle innerhalb Ihres Triggers erneut zu aktualisieren, was kompl ist. falsch. Aus diesem Grund erhalten Sie den Fehler. Sie können nicht dieselbe Tabelle ändern, auf die der Trigger ausgelöst wird. Der Zweck des Auslösers ist das automatische Auslösen, wenn die Tabelle in Ihrem Fall aktualisiert, eingefügt oder gelöscht wird. Was Sie brauchen, ist eine Prozedur, nicht ein Trigger.

6
Art

Selbst wir sind in unserem Projekt mit dem gleichen Thema gelandet. Nachdem wir in einigen Oracle-Foren gesucht hatten, haben wir die folgende Lösung gefunden.

1) Speichern Sie die Daten der alten/neuen Spalte in einer temporären Tabelle als Pat des Zeilen-Triggers .__) 2) Schreiben Sie einen Trigger auf Anweisungsebene und verwenden Sie die in Schritt 1 gespeicherten Daten.

Das würde das Problem lösen, denke ich.

0
user2988234

Ich hatte das gleiche Problem und bemerkte, dass wenn Sie eine Auswahl für dieselbe Tabelle vornehmen, auf die Sie den Auslöser setzen, dieses Problem auftreten kann/wird. Sie können FOR EACH ROW Daten in: Neu um die Berechnung durchzuführen (wenn möglich) und dann das Update durchzuführen.

In Ihrem Fall ist es sinnvoller, eine separate Tabelle zu verwenden, um das avg_grade pro Semester zu erhalten.

0
acostil

Wenn Sie andere Daten durch Verknüpfen einer anderen Tabelle (TABLE_ADDRESS) abrufen möchten. Hier ist meine Lösung.

 CREATE OR REPLACE TRIGGER TRIGGER_TABLE_ACTIVITIES AFTER  INSERT ON TABLE_NAME
     FOR EACH ROW
    DECLARE 
    V_ADDRESS VARCHAR2(100); 
    BEGIN 

            SELECT A.ADDRESS INTO V_ADDRESS 
            FROM TABLE_ADDRESS A
            WHERE A.ADDRESSID = :NEW.ADDRESSID
            ;
            INSERT INTO TABLE_ACTIVITIES(
                            NAME, ADDRESS)
            VALUES(:NEW.NAME, V_ADDRESS);
    END;
    /
0
user1238353