Чтение онлайн

на главную - закладки

Жанры

Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ

Борри Хелен

Шрифт:

Триггеры полезны для "автоматического заполнения" контекстной информацией столбцов, созданных для подобных целей. Firebird предоставляет множество контекстных переменных, которые вы можете использовать в операциях такого рода. Вы можете также использовать ваши собственные "флаги", которые вы вычисляете или просто поставляете в виде констант в процессе выполнения триггера.

В следующем примере мы используем триггер AFTER для множества событий с целью автоматического заполнения имени пользователя, даты, времени и идентификатора транзакции для помещения в файл протокола вместе с некоторой информацией

о событии. Поскольку регистрируется процесс, то, скорее всего, мы захотим выполнить это в самом конце; присвоим триггеру высокий последовательный номер:

CREATE TRIGGER AA_MEMBER FOR MEMBER

ACTIVE AFTER INSERT OR UPDATE OR DELETE

POSITION 99

AS

DECLARE VARIABLE MEM_ID INTEGER;

DECLARE VARIABLE DML_EVENT CHAR(4);

BEGIN

IF (DELETING) THEN

BEGIN

MEM_ID = OLD.MEMBER_ID;

DML_EVENT = 'DEL ';

END

ELSE

BEGIN

MEM_ID = NEW.MEMBER_ID;

IF (UPDATING) THEN

DML_EVENT = 'EDIT';

ELSE

DML_EVENT = 'NEW ';

END

INSERT INTO PROCESS_LOG (

TRANS_ID,

USER_ID,

MEMBER_ID,

DML_EVENT,

TIME_STAMP)

VALUES (

CURRENT_TRANSACTION,

CURRENT_USER,

:MEM_ID,

:DML_EVENT,

CURRENT_TIMESTAMP) ;

END ^

Конечно, вы также можете заполнять ваши новые или редактируемые строки непосредственно в триггере BEFORE.

Изменение других таблиц

В предыдущем примере мы увидели, как триггеры AFTER могут выполнять изменения в других таблицах для автоматизации управления такими задачами, как ведение протокола. Возможности расширить область действия события DML за пределы непосредственного контекста таблицы и строки, "владеющей" данными, имеют некоторые приложения для управления сложными отношениями.

Поддержание обязательного отношения

Обязательное отношение существует, когда две таблицы связаны через зависимость внешнего ключа и должна существовать по меньшей мере одна строка для каждой первичной строки. Поскольку SQL не предоставляет ограничения "обязательности", нужна логика триггера для осуществления правила "минимум один потомок" не только во время создания, но и при удалении зависимых строк.

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

Во-первых, создадим две таблицы:

CREATE TABLE MASTER (

ID INTEGER NOT NULL PRIMARY KEY,

DATA VARCHAR(10));

COMMIT;

CREATE TABLE DETAIL (

ID INTEGER NOT NULL PRIMARY KEY,

MASTER_ID INTEGER,

/* Столбец внешнего ключа сознательно сделан в виде, допускающем пустое значение */

DATA VARCHAR(10),

TEMP_FK INTEGER,

CONSTRAINT FK_MASTER FOREIGN KEY(MASTER_ID)

REFERENCES MASTER

ON DELETE CASCADE);

COMMIT;

Когда приложение посылает (post) строки главной

и подчиненной таблиц, оно вначале будет передавать подчиненные строки со значением NULL в столбце внешнего ключа и со значением первичного ключа главной таблицы в столбце TEMP FK.

Затем нам нужно исключение, которое будет возникать при попытке нарушения правила обязательности и при удалении последней подчиненной строки. Мы также создадим генератор для подчиненной строки.

CREATE EXCEPTION CANNOT_DEL_DETAIL

'This is the only detail record: it can not be deleted.';

/* Это единственная подчиненная запись: она не может быть удалена */

CREATE GENERATOR GEN_DETAIL;

COMMIT;

Следующий триггер проверяет подчиненную таблицу после добавления новой версии главной записи. Он может "видеть" подчиненные строки, ранее посланные в той же транзакции, которые имеют значение первичного ключа (NEW.ID) В столбце TEMP FK. В случае изменения, в отличие от добавления, он также может определить подчиненные строки, которыми уже "владеет" главная строка. Любые строки, которые соответствуют условию TEMP_FK, получают значение их внешнего ключа, а TEMP_FK устанавливается в NULL.

Если не найдено строк, соответствующих этому условию, то триггер добавляет "пустую" подчиненную строку.

SET TERM ^;

CREATE TRIGGER AI_MASTER FOR MASTER

ACTIVE AFTER INSERT OR UPDATE POSITION 1

AS

BEGIN

IF (NOT (EXISTS (

SELECT 1 FROM DETAIL WHERE MASTER_ID = NEW.ID

OR TEMP_FK = NEW.ID))) THEN

INSERT INTO DETAIL (MASTER_ID)

VALUES (NEW.ID);

ELSE

IF (NOT (EXISTS (

SELECT 1 FROM DETAIL WHERE MASTER_ID = NEW.ID))) THEN

UPDATE DETAIL SET

MASTER_ID = NEW.ID,

TEMP_FK = NULL

WHERE TEMP_FK = NEW.ID;

END ^

Подчиненная таблица получает автоматически сгенерированный ключ:

CREATE TRIGGER BI_DETAIL FOR DETAIL

ACTIVE BEFORE INSERT AS

BEGIN

IF (NEW.ID IS NULL) THEN

NEW.ID = GEN_ID(GEN_DETAIL, 1);

END ^

Следующий триггер BEFORE DELETE для подчиненной таблицы не позволит удалить строку, если она единственная:

CREATE TRIGGER BD_DETAIL FOR DETAIL

ACTIVE BEFORE DELETE POSITION 0

AS

BEGIN

IF (NOT (EXISTS (

SELECT 1 FROM DETAIL

WHERE MASTER_ID = OLD.MASTER_ID

AND ID <> OLD.ID)))

THEN

EXCEPTION CANNOT_DEL_DETAIL;

END ^

Сейчас у нас ситуация, когда обязательное отношение защищено настолько хорошо, что при попытке удалить главную строку этот триггер не позволит выполнить каскадное удаление. Нам нужно еще два триггера для главной таблицы, расширяющие действия триггеров, созданных системой для каскадного удаления. В триггере BEFORE DELETE для главной таблицы мы заполняем пустым значением внешний ключ подчиненной таблицы и устанавливаем значение столбца TEMP FK. После того как будет

Поделиться:
Популярные книги

Княжий человек

Билик Дмитрий Александрович
3. Бедовый
Фантастика:
юмористическая фантастика
городское фэнтези
мистика
5.00
рейтинг книги
Княжий человек

Отмороженный 6.0

Гарцевич Евгений Александрович
6. Отмороженный
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Отмороженный 6.0

Жатва душ. Остров мертвых

Сугралинов Данияр
Фантастика:
боевая фантастика
рпг
5.20
рейтинг книги
Жатва душ. Остров мертвых

Имперец. Земли Итреи

Игнатов Михаил Павлович
11. Путь
Фантастика:
героическая фантастика
боевая фантастика
5.25
рейтинг книги
Имперец. Земли Итреи

Стражи душ

Кас Маркус
4. Артефактор
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Стражи душ

Тепла хватит на всех

Котов Сергей
1. Миры Пентакля
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Тепла хватит на всех

Возвращение демонического мастера. Книга 1

Findroid
1. Вселенная Вечности
Фантастика:
фэнтези
5.75
рейтинг книги
Возвращение демонического мастера. Книга 1

На границе империй. Том 4

INDIGO
4. Фортуна дама переменчивая
Фантастика:
космическая фантастика
6.00
рейтинг книги
На границе империй. Том 4

Кодекс Крови. Книга ХVI

Борзых М.
16. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХVI

Я сделаю это сама

Кальк Салма
1. Магический XVIII век
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Я сделаю это сама

Я граф. Книга XII

Дрейк Сириус
12. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я граф. Книга XII

Неудержимый. Книга VI

Боярский Андрей
6. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга VI

Как я строил магическую империю 3

Зубов Константин
3. Как я строил магическую империю
Фантастика:
попаданцы
постапокалипсис
аниме
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 3

Девятый

Каменистый Артем
1. Девятый
Фантастика:
боевая фантастика
попаданцы
9.15
рейтинг книги
Девятый