Вызов Oracle после вставки или удаления

Извините за мой английский.

У меня есть 2 таблицы:

Table1 id table2_id num modification_date 

а также

 Table2 id table2num 

Я хочу создать триггер, который после вставки или удаления в Table1 обновляет последнее значение num в Table2.table1lastnum .

Мой триггер:

 CREATE OR REPLACE TRIGGER TABLE1_NUM_TRG AFTER INSERT OR DELETE ON table1 FOR EACH ROW BEGIN IF INSERTING then UPDATE table2 SET table2num = :new.num WHERE table2.id = :new.table2_id; ELSE UPDATE table2 SET table2num = (SELECT num FROM (SELECT num FROM table1 WHERE table2_id = :old.table2_id ORDER BY modification_date DESC) WHERE ROWNUM <= 1) WHERE table2.id = :old.table2_id; END IF; END TABLE1_NUM_TRG; 

Но после удаления в Table1 меня есть ошибка:

 ORA-04091: table BD.TABLE1 is mutating, trigger/function may not see it ORA-06512: at "BD.TABLE1_NUM_TRG", line 11 ORA-04088: error during execution of trigger 'BD.TABLE1_NUM_TRG' 

Что я делаю не так?

То, что вы столкнулись, – это classическое исключение «mutating table». В триггере ROW Oracle не позволяет запускать запрос к таблице, на которой установлен триггер – так что это SELECT против TABLE1 в части DELETING триггера, которая вызывает эту проблему.

Есть несколько способов обойти это. Возможно, лучшим в этой ситуации является использование сложного триггера, который будет выглядеть примерно так:

 CREATE OR REPLACE TRIGGER TABLE1_NUM_TRG FOR INSERT OR DELETE ON TABLE1 COMPOUND TRIGGER TYPE NUMBER_TABLE IS TABLE OF NUMBER; tblTABLE2_IDS NUMBER_TABLE; BEFORE STATEMENT IS BEGIN tblTABLE2_IDS := NUMBER_TABLE(); END BEFORE STATEMENT; AFTER EACH ROW IS BEGIN IF INSERTING THEN UPDATE TABLE2 t2 SET t2.TABLE2NUM = :new.NUM WHERE t2.ID = :new.TABLE2_ID; ELSIF DELETING THEN tblTABLE2_IDS.EXTEND; tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.TABLE2_ID; END IF; END AFTER EACH ROW; AFTER STATEMENT IS BEGIN IF tblTABLE2_IDS.COUNT > 0 THEN FOR i IN tblTABLE2_IDS.FIRST..tblTABLE2_IDS.LAST LOOP UPDATE TABLE2 t2 SET t2.TABLE2NUM = (SELECT NUM FROM (SELECT t1.NUM FROM TABLE1 t1 WHERE t1.TABLE2_ID = tblTABLE2_IDS(i) ORDER BY modification_date DESC) WHERE ROWNUM = 1) WHERE t2.ID = tblTABLE2_IDS(i); END LOOP; END IF; END AFTER STATEMENT; END TABLE1_NUM_TRG; 

Сложный триггер позволяет обрабатывать каждую временную точку ( BEFORE STATEMENT , BEFORE ROW , AFTER ROW и AFTER STATEMENT ). Обратите внимание, что точки синхронизации всегда вызывается в указанном порядке. Когда выполняется соответствующий оператор SQL (то есть INSERT INTO TABLE1 или DELETE FROM TABLE1 ), и этот триггер запускается, первая выбранная точка времени, которая будет вызываться, будет BEFORE STATEMENT , а код в обработчике BEFORE STATEMENT будет выделять таблицу PL / SQL для держите кучу чисел. В этом случае номера, которые должны быть сохранены в таблице PL / SQL, будут значениями TABLE2_ID из таблицы 1. (Вместо таблицы, например, массива используется таблица PL / SQL, поскольку таблица может содержать различное количество значений, а если мы использовали массив, нам нужно заранее знать, сколько чисел нам нужно хранить. Мы не можем заранее знать, сколько строк будет зависеть от конкретного оператора, поэтому мы используем таблицу PL / SQL). Когда достигается момент времени AFTER EACH ROW и мы обнаруживаем, что обрабатываемый оператор является INSERT, триггер просто идет вперед и выполняет необходимое UPDATE в TABLE2, так как это не вызовет проблемы. Однако, если выполняется DELETE, триггер сохраняет TABLE1.TABLE2_ID в таблицу PL / SQL, выделенную ранее. Когда окончательная точка времени AFTER STATEMENT наконец достигнута, таблица PL / SQL, выделенная ранее, выполняется итерацией, и для каждого найденного TABLE2_ID выполняется соответствующее обновление.

Документация здесь .

Поделитесь и наслаждайтесь.

Вы должны определить перед триггером для удаления. Попробуйте использовать два триггера

 CREATE OR REPLACE TRIGGER INS_TABLE1_NUM_TRG AFTER INSERT ON table1 FOR EACH ROW BEGIN UPDATE table2 SET table2num = :new.num WHERE table2.id = :new.table2_id; END INS_TABLE1_NUM_TRG; CREATE OR REPLACE TRIGGER DEL_TABLE1_NUM_TRG BEFORE DELETE ON table1 FOR EACH ROW BEGIN UPDATE table2 SET table2num = (SELECT num FROM (SELECT num FROM table1 WHERE table2_id = :old.table2_id ORDER BY modification_date DESC) WHERE ROWNUM <= 1) WHERE table2.id = :old.table2_id; END DEL_TABLE1_NUM_TRG; 
  • могу ли я запустить триггер для оператора select в mysql?
  • Событие изменения триггера () при установке значения с помощью функции val ()
  • mysql после триггера вставки, который обновляет столбец другой таблицы
  • Обновлять материализованное представление автоматически с помощью правила или уведомлять
  • Как получить столбец с последовательными, увеличивающимися номерами, без каких-либо чисел?
  • ТРИГГЕРЫ, которые приводят к сбою INSERT? Возможное?
  • Давайте будем гением компьютера.