14

这是问题所在:

创建一个触发器,以防止对录取关系进行任何更改,从而将任何特定班级的总体平均成绩降至 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)

我在这些触发器上度过了一段糟糕的时光,但这是我尝试完成这项工作的尝试:

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;   
/

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

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'

有什么建议吗?我正在使用甲骨文。

4

6 回答 6

16

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

您的触发器是 AFTER UPDATE OR INSERT OR DELETE。意味着如果您在此表上运行 UPDATE OR INSERT OR DELETE 语句,触发器将触发。但是您正尝试在触发器中再次更新同一个表,这是 compl。错误的。这就是您收到错误的原因。您不能修改触发器正在触发的同一个表。触发器的目的是在您的情况下更新、插入或删除表时自动触发。你需要的是一些程序,而不是触发器。

于 2013-04-24T12:58:27.533 回答
15

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

pragma autonomous_transaction;
于 2016-07-12T11:16:10.190 回答
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;  
于 2013-04-24T02:27:18.757 回答
3

我遇到了同样的问题,我注意到如果您在同一张桌子上进行选择,您可能会/将会遇到这个问题。您可以删除FOR EACH ROW 或使用:New中的数据进行计算(如果可能),然后进行更新。

在您的情况下,使用单独的表格来获得每学期的 avg_grade 会更有意义。

于 2015-08-25T19:35:09.810 回答
0

即使我们在我们的项目中也遇到了同样的问题。但是在几个oracle论坛搜索后,我们找到了以下解决方案。

1)将旧/新列数据保存在临时表中,作为行级触发器的一部分。2)编写语句级触发器,使用步骤1中保存的数据。

这将解决我认为的问题。

于 2016-07-04T09:36:52.283 回答
0

如果您想通过连接其他表(TABLE_ADDRESS)来检索其他数据。这是我的解决方案。

 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;
    /
于 2019-07-26T14:19:47.140 回答