При внедрении триггера на уровне инструкций в таблице можно получить OLD и NEW записи для всех затронутых строк?
В Oracle вы можете написать триггер уровня, указав предложение FOR EACH ROW
в инструкции CREATE TRIGGER
:
CREATE TRIGGER MY_FANCY_TRIGGER
BEFORE UPDATE ON MY_TABLE
FOR EACH ROW
BEGIN
IF :OLD.my_id_column > 4 AND :NEW.some_other_column <> 'foo' THEN
-- ...
END IF;
END;
Такой триггер позволяет просматривать версии до и после каждой затронутой строки (:OLD
и :NEW
соответственно). Например, следующий оператор заставит этот триггер выполнить один раз для каждой строки в MY_TABLE
:
UPDATE MY_TABLE SET some_other_column = 'bar';
Исключив предложение FOR EACH ROW
, триггер становится триггером уровня инструкций. Это означает, что он выполняется только один раз за оператор, независимо от того, сколько строк (если они есть) повлияло на оператор. К сожалению, триггеры уровня инструкций не имеют доступных переменных :OLD
и :NEW
(потому что количество затронутых строк много меняется).
Можно ли получить значения :OLD
и :NEW
для всех затронутых строк внутри триггера на уровне инструкций? У меня есть некоторая обработка, которую я бы предпочел только раз за один оператор.
Ответы
Ответ 1
Один из подходов - это тот, который предложил Джастин Кейв хранить информацию в триггерах уровня в отдельных коллекциях пакетов.
Если вы используете 11g, то правильным подходом будет использование сложных триггеров. Это позволяет избежать создания отдельного пакета для хранения коллекции ключей - это можно сделать в самом триггере,
Ответ 2
Не напрямую, нет.
Стандартным подходом является "решение с тремя триггерами" (более часто используемое, когда вы пытаетесь обойти проблему с мутирующей таблицей)
- Создайте пакет, содержащий набор ключей для вашей таблицы
- Создайте триггер before, инициализирующий коллекцию
- Создайте триггер уровня, который вставляет ключи в коллекцию.
- Создайте триггер после оператора, который использует ключи в коллекции для выполнения своей обработки.
Очевидно, что в вашем случае это, вероятно, просто усложняет процесс, если триггер уровня строки не вызывает ошибку с измененной таблицей.
Как показывает josephj1989 ниже, если вы используете 11g, вы можете использовать составные триггеры, чтобы немного упростить это. Вы по-прежнему будете объявлять коллекцию, заполнять коллекцию в триггерном уровне на уровне строки и обрабатывать коллекцию в триггере уровня инструкций. Но для создания и управления, а не для нескольких объектов будет только один объект.