表是变异的,触发器/功能可能看不到它(停止平均等级从低于2.5下降)

The*_*ist 11 sql oracle triggers

这是问题所在:

创建一个触发器,以防止对任何特定类中低于2.5的整体平均等级的接受关系进行任何更改.注意:此触发器不是为了解决任何给定学生的平均GPA,而是应该针对特定班级中指定的所有成绩的平均成绩.

这是架构:

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)
Run Code Online (Sandbox Code Playgroud)

我在这些触发器上度过了一段可怕的时光,但这是我努力做到这一点:

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;   
/
Run Code Online (Sandbox Code Playgroud)

我显然做错了,因为当我去更新或删除元组时,我得到错误:

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'
Run Code Online (Sandbox Code Playgroud)

有什么建议?我正在使用Oracle.

小智 14

在里面使用这个语句DECLARE,它会起作用.

pragma autonomous_transaction;
Run Code Online (Sandbox Code Playgroud)

  • 这将抑制错误,但触发器可能仍然无法正确运行,就像我的情况一样。 (4认同)
  • 您的解决方案对我有用。对于其他遇到相同问题的人,可以理解为什么会发生这种情况:ORA-04091原因:触发器(或此语句中引用的用户定义的PL / SQL函数)试图查看(或修改)表中的表。被触发它的语句修改的中间部分。行动:重写触发器(或函数),使其不读取该表。来源:http://docs.oracle.com/cd/B10501_01/server.920/a96525/e2100.htm#1002387 (2认同)

Art*_*Art 9

首先,您需要阅读有关触发器,变异表错误和复合触发器的信息:http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

您的触发器是更新或插入或删除后.表示如果在此表上运行UPDATE OR INSERT OR DELETE语句,则触发器将触发.但是你试图在你的触发器内再次更新同一个表,这是compl.错误.这就是您收到错误的原因.您无法修改触发器触发的同一个表.触发器的目的是在您的情况下更新,插入或删除表时自动触发.你需要的是一些程序,而不是触发器.


Gor*_*off 6

我认为您可以通过将其重写为触发器而不是触发器来解决此问题。但是,这对于插入和删除可能有点复杂。这个想法是:

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;  
Run Code Online (Sandbox Code Playgroud)