web-dev-qa-db-ja.com

テーブルが変化しているため、トリガー/機能が表示されない場合があります(平均評点が2.5を下回らないようにする)

問題は次のとおりです。

特定のクラスの全体的な平均評点が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'

何かアドバイス? Oracleを使用しています。

10
The Rationalist

これを修正するには、afterトリガーではなくbeforeトリガーとしてこれを書き換えればよいと思います。ただし、これは挿入および削除では少し複雑になる場合があります。アイデアは次のとおりです。

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

DECLARE内でこのステートメントを使用すると、動作します。

pragma autonomous_transaction;
13
Sweta

まず、トリガー、変化するテーブルエラー、複合トリガーについて読む必要があります。 http://docs.Oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

トリガーはAFTER UPDATE OR INSERT OR DELETE。UPDATE OR INSERT ORこのテーブルのDELETEステートメント、トリガーは起動しますが、トリガー内で同じテーブルを再度更新しようとしていますが、これは間違いです。これがエラーの原因です。トリガーが起動しているテーブルトリガーの目的は、テーブルが更新、挿入、または削除されたときに自動的に起動することです。

9
Art

私は同じ問題を抱えていて、同じテーブルで選択を行うと、トリガーを置くと、この問題が発生する可能性があることに気付きました。 FOR EACH ROWを削除するか、:Newのデータを使用して計算を行い(可能な場合)、更新を行うことができます。

あなたの場合は、学期ごとにavg_gradeを設定するために別のテーブルを使用する方が理にかなっています。

2
acostil

私たちのプロジェクトでも同じ問題が発生しました。しかし、いくつかのOracleフォーラムで検索した結果、以下のソリューションが見つかりました。

1)古い/新しい列のデータを、行レベルトリガーの一部として一時テーブルに保存します。 2)ステートメントレベルトリガーを記述し、手順1で保存したデータを使用します。

これは私が考える問題を解決するでしょう。

0
user2988234

他のテーブル(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;
    /
0
user1238353