Таблица мутирует, триггер / функция может ее не видеть (останавливая падение среднего балла ниже 2,5)



Вот в чем проблема:



Создайте триггер, который предотвращает любое изменение отношения принятия, которое снизило бы общую среднюю оценку в любом конкретном классе ниже 2,5. Примечание: этот триггер не предназначен для оценки среднего балла любого конкретного учащегося, а скорее он должен учитывать средний балл для всех оценок, присвоенных в конкретном классе.



Вот схема:



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.

737   5  

5 ответов:

Я думаю, что вы можете исправить это, переписав это как перед триггером, а не после триггера. Однако это может быть немного сложно для вставок и удалений. Идея такова:

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;  

Используйте это утверждение внутри DECLARE, оно будет работать.

pragma autonomous_transaction;

Сначала вам нужно прочитать о триггерах, мутирующей ошибке таблицы и составных триггерах: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

Ваш триггер находится после обновления, вставки или удаления. Означает, что при выполнении инструкций UPDATE, INSERT или DELETE в этой таблице срабатывает триггер. Но вы пытаетесь обновить ту же таблицу снова внутри вашего триггера, который является компл. неправильный. Вот почему вы получаете ошибку. Вы не можете изменить то же самое стол, на котором срабатывает спусковой крючок. Цель триггера-автоматически срабатывать при обновлении, вставке или удалении таблицы в вашем случае. Вам нужна какая-то процедура, а не триггер.

У меня была та же проблема, и я заметил, что если вы сделаете выбор на той же таблице, на которую вы ставите триггер, вы можете/получите эту проблему. Вы можете удалить для каждой строки или используйте данные в : New , чтобы сделать расчет (если это возможно), а затем сделать обновление.

В вашем случае будет более разумно использовать отдельную таблицу, чтобы иметь оценку avg_grade за семестр.

Даже мы закончили с той же проблемой в нашем проекте. Но после поиска в нескольких форумах oracle, мы нашли следующее решение.

1) сохраните Старые / новые данные столбца во временной таблице как pat триггера уровня строки. 2) Напишите триггер уровня оператора и используйте данные, сохраненные в шаге 1.

Это решило бы проблему, я думаю.

Comments

    Ничего не найдено.