Значения old и new
Значение OLD.ИмяСтолбца позволяет обратиться к состоянию столбца, имевшему место до внесения изменений, а значение NEW.ИмяСтолбца — к состоянию столбца после внесения изменений.
Например, механизм обеспечения ссылочной целостности "cascade", в случае изменения значения первичного ключа родительской таблицы, на мнемоническом языке можно описать так:
IF (OLD.PrimaryKeyPoдитeля <> NEW.РгimагуКеуРодителя) THEN
UPDATE ДочерняяТаблица
SET ForeignКеуДочернейТаблицы = NEW.РгimагуКеуРодителя
WHERE ForeignКеуДочернейТаблицы = OLD.PrimaryKeyРодителя;
В качестве примера приведем код триггера для родительской таблицы Realty, который при изменении значения ее первичного ключа будет автомагически изменять значение внешнего ключа дочерней таблицы Lease. Другими словами, если в таблице Realty изменилось значение поля Adr, то триггер изменит значение поля Adr в оответствующей записи таблицы Lease.
CREATE TRIGGER UPDAT_REALTY FOR Realty
ACTIVE BEFORE UPDATE
AS
BEGIN IF (OLD.Adr <> NEW.Adr)
THEN UPDATE Lease
SET Adr = NEW.Adr
WHERE Adr = OLD.Adr;
END В том случае, если значение в столбце не изменилось, то OLD.ИмяСтолбца будет равно
EW.ИмяСтолбца. Проверим вышеизложенное.
Запустите утилиту Interactive SQL.
Создайте триггер UPDAT_REALTY.
Попробуйте изменить значение адреса в таблице Realty. Это не удается. Дело в том, что сервер InterBase поддерживает механизм обеспечения ссылочной целостности "prohibit". В данном случае он реализован на основании декларации связи таблиц FOREIGN KEY (AdR) REFERENCES Realty (AdR) в скрипте tables.sql при создании таблицы Lease.
Удалите эту связь (ограничение INTEG_7):
ALTER TABLE Lease
DROP CONSTRAINT INTEG_7
Можете убедиться, что она отсутствует: теперь таблица Lease не связана с Realty.
Измените значение адреса в таблице Realty.
Как видите, теперь при изменении значения ее первичного ключа триггер автоматически изменяет значение внешнего ключа дочерней таблицы Lease. Другими словами, реализован механизм обеспечения ссылочной целостности "cascade".
Примеры использования триггера
Рассмотрим использование триггера для реализации ограничений ссылочной целостности и для занесения в ключевые столбцы уникальных значений. В связи с тем, что InterBase не поддерживает автоинкрементные поля, при создании ключевого столбца, требующего уникальности значений, рекомендуется поступать так:
1. При создании таблицы задать ключевой столбец целочисленного типа.
2. Создать генератор, который при обращении к нему возвращает уникальное целочисленное значение.
3. Создать триггер, который при добавлении к таблице новой записи обращается к генератору и заносит возвращаемое им значение в ключевое поле.
Следующий пример иллюстрирует описанную последовательность действий:
/* Создание таблицы */
CREATE TABLE Store
(S_Code INTEGER NOT NULL,
...PRIMARY KEY (S_Code));
/* Создание генератора */
CREATE GENERATOR GenStore;
SET GENERATOR GenStore TO 1;
/* Создание триггера */
CREATE TRIGGER CodeStOre FOR Store
ACTIVE BEFORE INSERT
AS BEGIN NEW.S_Code = GEN_ID(GenStore, 1);
END
После добавления к таблице store новой записи ключевому столбцу s_Сode этой записи автоматически присваивается уникальное значение. Это обеспечивается обращением GEN_ID к генератору GenStore, который создается отдельно от триггера (работа с генераторами рассмотрена ниже).
Ограничения ссылочной целостности для связанных таблиц включают в себя:
каскадное удаление записей;
запрет на редактирование ключевых столбцов.
Рассмотрим, как можно реализовать каскадное удаление записей с участием триггера.
Пусть имеются две таблицы: главная Store и подчиненная Cards, связанные по полям кода s_code и c_code2 соответственно:
CREATE TABLE Store
(S_Code INTEGER NOT NULL,
... PRIMARY KEY (S_Code));
CREATE TABLE Cards
(C_Code INTEGER NOT NULL,
C_Code2 INTEGER NOT NULL,
PRIMARY KEY (C_Code) ) ;
Каскадное удаление записей для связанных таблиц заключается в том, что если из главной таблицы удаляется запись, то и в подчиненной таблице должны быть удалены все соответствующие ей записи.
В нашем случае это выполняется следующим образом:
CREATE TRIGGER DeleteStore FOR Store
ACTIVE
AFTER DELETE
AS
BEGIN DELETE FROM Cards WHERE Store.S_Code = Cards.C_Code2;
END После удаления записи в таблице store (склад) будут автоматически удалены все
соответствующие записи в таблице Cards (движение товара).
