При внедрении триггера на уровне инструкций в таблице можно получить 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, вы можете использовать составные триггеры, чтобы немного упростить это. Вы по-прежнему будете объявлять коллекцию, заполнять коллекцию в триггерном уровне на уровне строки и обрабатывать коллекцию в триггере уровня инструкций. Но для создания и управления, а не для нескольких объектов будет только один объект.