Как создать два триггера, которые запускают друг друга и ограничить их запуск двумя разами?
Как создать два триггера, которые запускают друг друга и ограничить их запуск двумя разами?
Понимаю, как триггеры могут запускать друг друга. Например, есть на двух таблицах по триггеру реагирующих на insert, и когда один из них срабатывает он добавляет запись в другую таблицу, тем самым активирует второй триггер, который добавляет строку в первую таблицу и т.д.
Но не понимаю, как можно ограничить их запуск двумя разами. Помогите, пожалуйста.
Ответы (2 шт):
Создайте переменные сессии, вот так:
create or replace package trigcontrol as
type callcounters is record (t1 int := 0, t2 int := 0);
calls callcounters;
end;
И ведите в них подсчёт рекурсивных вызовов. Пример реализации триггера:
create or replace trigger t1trig before insert on t1 for each row
begin
if trigcontrol.calls.t1 = 2 then
raise_application_error (-20000, 'trigcontrol.calls.t1==2');
end if;
trigcontrol.calls.t1 := trigcontrol.calls.t1+1;
insert into t2 values (:new.col);
trigcontrol.calls.t1 := 0;
exception when others then
trigcontrol.calls.t1 := 0;
raise;
end;
PS Это не решение для реального проекта, только для демонстрации в процессе обучения.
Примитивное решение: добавить в каждую таблицу поле-флаг (например, FROM_TRIGGER number(1) default 0), которое будет определять проставлено ли значение из другого триггера или нет.
Соответственно, в триггерах проверять флаг и добавлять записи в зависимости от него. Так можно контролировать в каких случаях добавляется новая строка, а в каких нет.
CREATE OR REPLACE TRIGGER t1_before_insert
BEFORE INSERT
ON t1
FOR EACH ROW
BEGIN
IF :new.from_trigger = 0 THEN
--Добавляем запись
INSERT INTO t2(..., from_trigger)
VALUES(..., 1);
END IF
END;
Аналогично для второй таблицы. Если нужна более сложная логика, то можно назвать поле TRIGGER_ACTION и использовать для него больше разных значений.