- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ - Хелен Борри
Шрифт:
Интервал:
Закладка:
* Индикатор фазы, BEFORE или AFTER, определяющий момент, когда триггер будет выполняться при событии DML.
* Индикатор события DML определяет тип операции SQL, при которой будет выполняться триггер: INSERT, UPDATE или DELETE.
* В Firebird 1.0.x может быть указан индикатор ровно одного события. Начиная с версии 1.5, необязательное расширение <событие> OR <событие> ... позволяет задавать два или три события в одном модуле. Например, ... BEFORE INSERT OR UPDATE OR DELETE ... позволяет вам задать действия для всех трех событий. Логические контекстные переменные INSERTING, UPDATING или DELETING поддерживают логику переходов.
* Необязательный индикатор последовательности, POSITION число, определяет момент запуска триггера по отношению к другим триггерным модулям для той же фазы и события.
Тело триггера
Во всех кодах модулей Firebird тело состоит из необязательного объявления списка локальных переменных, за которым следует блок операторов. Программирование тела триггера в точности такое же, как и программирование тела процедуры (см. главу 30). Интерес для нас в этой главе представляют некоторые специальные расширения PSQL, осуществляющие поддержку контекста триггера, и некоторые особые роли триггеров по реализации и поддержке бизнес-правил.
Триггеры могут вызывать хранимые процедуры. Правила вызова для триггеров в точности такие же, что и для хранимых процедур. Техники обработки исключений обсуждаются в главе 32.
Триггеры могут использовать курсоры, выполнять операции с другими таблицами и отправлять события. Они могут вызывать и обрабатывать исключения, включая те, которые возникли во вложенных процедурах.
Триггеры никогда не вызываются процедурами, другими триггерами или приложениями. Они совсем не поддерживают входные и выходные аргументы.
Особенности PSQL для триггеров
Два особых элемента PSQL доступны триггерам: логические контекстные переменные событий INSERTING, UPDATING и DELETING и контекстные переменные NEW и OLD.
Переменные события
В Firebird появляются логические контекстные переменные INSERTING, UPDATING и DELETING, чтобы поддерживать условные переходы для триггеров, используемых для нескольких событий. Возможным синтаксисом ветвления может быть:
IF ({INSERTING | UPDATING | DELETING}
OR {UPDATING | DELETING | INSERTING}
[OR {DELETING | INSERTING | UPDATING}]) THEN ...
Работа этих полезных предикатов иллюстрируется в дальнейших примерах этой главы.
Переменные NEW и OLD
Контекстные переменные NEW и OLD являются расширениями PSQL, специфичными для триггеров[120]; они позволяют ссылаться на существующие ("старые") и требуемые ("новые") значения каждого столбца. Переменные NEW.* имеют значения в событиях INSERT и UPDATE; переменные OLD.* имеют значения в событиях UPDATE и DELETE, NEW.* в событиях удаления и OLD.* В событиях добавления имеют значение NULL. Применимые значения NEW и OLD доступны для всех столбцов таблицы или просмотра, даже если сами столбцы не указаны в операторе DML.
Значения OLD.* (если доступны) могут использоваться в триггерах как переменные, но изменение значения не влияет на сохраненное старое значение[121]. Значения NEW.* (если доступны) могут использоваться для чтения/записи в фазе BEFORE и только для чтения в фазе AFTER. Если вы хотите манипулировать ими как переменными значениями в триггере AFTER, присвойте их значения локальным переменным и обращайтесь к этим локальным переменным.
Использование NEW и OLDДля использования мощи триггеров Firebird в разработке баз данных при отслеживании целостности данных, независимо от людей и внешних программ, переменные NEW и OLD являются основным инструментом. Они могут быть использованы для:
* получения допустимых значений по умолчанию в некоторых условиях;
* проверки и при необходимости преобразования входных данных пользователя;
* получения ключей и значений для выполнения автоматических обновлений в других таблицах;
* реализации автоинкрементных ключей средствами генераторов.
Новые значения для строки могут быть изменены только в действиях BEFORE. Если триггер, запускаемый в фазе AFTER, попытается присвоить значение столбцу NEW, это не даст никакого результата.
Все значения NEW можно перезаписывать в фазе BEFORE, они немедленно принимают новые назначенные им значения. Новая версия записи получит переназначенные значения, только когда все триггеры BEFORE будут завершены. С этого момента значения NEW становятся значениями только для чтения. Следовательно, если у вас несколько триггеров изменяют одни и те же значения NEW, важно, чтобы все они имели различные номера POSITION, правильно упорядоченные.
Реализация автоинкрементных ключейРекомендованное использование в Firebird триггеров BEFORE INSERT - реализация в стиле @IDENTITY автоинкрементных первичных ключей. Эта техника проста, и большинство разработчиков Firebird могут написать такие триггеры во сне. Она включает два шага:
1. Создание генератора для генерации уникальных чисел ключа.
2. Написание триггера BEFORE INSERT для таблицы.
Для иллюстрации этой техники мы реализуем автоинкрементный первичный ключ для таблицы CUSTOMER, у которой первичный ключ CUSTOMER_ID- столбец целого типа BIGINT (версия 1.5) или NUMERIC(18,0) (версия 1.0.x). В диалекте 1 базы данных CUSTOMER_ID должен иметь тип INTEGER.
Во-первых, создадим генератор:
CREATE GENERATOR GEN_PK_CUSTOMER;
Затем создадим триггер:
CREATE TRIGGER BI_CUSTOMER FOR CUSTOMER
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.CUSTOMER_ID IS NULL) THEN
NEW. CUSTOMER_ID = GEN_ID (GEN_PK_CUSTOMER, 1) ;
END ^
COMMIT ^
Когда выполняется добавление, CUSTOMER ID сознательно не указывается во входном списке оператора INSERT:
INSERT INTO CUSTOMER (
LAST_NAME,
FIRST_NAME,
...)
VALUES (?, ?, ...);
Без триггера этот оператор вызовет исключение, потому что первичный ключ не может иметь пустого значения. Однако триггер BEFORE INSERT выполняется до проверки этого ограничения, он контролирует, что CUSTOMER ID имеет пустое значение, и выполняет свое действие.
Зачем проверять NEW.значение на NULLЕсли триггер может делать это для меня, то вы можете спросить, зачем нужно выполнять проверку на NULL?
Для приложения может быть полезным знать, какое будет значение первичного ключа новой строки без необходимости ожидать завершения транзакции. Например, это общее требование при создании "главной" записи и связи с ней "подчиненных" записей обычно с помощью внешнего ключа в одной транзакции. Довольно неуклюже - а иногда и рискованно - нарушать атомарность задачи создания главная- подчиненная, подтверждая создание главной для получения необходимого вам значения внешнего ключа для подчиненных записей, полагаясь только на триггер.
Приложения, написанные для Firebird, имеют преимущества, благодаря одной особой характеристике генераторов: они не зависят от пользовательских транзакций. Однажды сгенерированное значение не может быть выдано ни одной другой транзакции и не может быть отменено.
Быстрый запрос в его собственной транзакции[122] возвращает значение
SELECT GEN_ID (GEN_PK_CUSTOMER, 1) AS RESULT
FROM RDB$DATABASE;
Если в вашем триггере опущена проверка на пустое значение и просто выполняется:
. . .
AS
NEW.CUSTOMER_ID = GEN_ID (GEN_PK_CUSTOMER, 1);
END ^
то значение, полученное приложением, будет перекрыто вторым "дерганьем" генератора, что нарушит связь с подчиненными записями.
Эта ситуация не является аргументом в пользу генерации ключей только в триггерах. Наоборот, триггер с проверкой на NULL обеспечивает реализацию бизнес-правил при любых условиях.
! ! !
ВНИМАНИЕ! В разработках, где нет хорошей интеграции работы приложений различных разработчиков, или где пользователи имеют свободный доступ к базе данных при использовании инструментов запросов, может оказаться необходимым включение в ваши триггеры более высокого уровня защиты целостности ключей, такого как контроль принадлежности диапазону или другая подходящая форма проверки.
. ! .
ПреобразованияПеременная NEW может быть использована для преобразования значения в нечто другое. Общий трюк заключается в использовании триггера (или пары триггеров в версии 1.0.А-) для поддержания "заменителя" столбца для выполнения нечувствительных к регистру поисков по другому столбцу, который может содержать смешанные значения регистра. Триггер читает значение NEW столбца со смешанным регистром, конвертирует его в верхний регистр и записывает в значение NEW столбца поиска. Такой столбец-"заменитель" должен иметь ограничение NOT NULL для гарантии того, что в нем всегда будет значение для поиска:
CREATE TABLE MEMBER (
MEMBER_ID INTEGER NOT NULL PRIMARY KEY,
LAST_NAME VARCHAR (40) NOT NULL,
FIRST_NAME VARCHAR (35),
PROXY_LAST_NAME VARCHAR (40),
MEMBER_TYPE CHAR(3) NOT NULL,
MEMBERSHIP_NUM VARCHAR(13) ,
. . . . );
COMMIT;
/* */
SET TERM ^;
CREATE TRIGGER BA_MEMBER1 FOR MEMBER
ACTIVE BEFORE INSERT OR UPDATE
POSITION 0
AS
BEGIN
. . .
NEW. PROXY_LAST_NAME = UPPER(NEW.LAST_HAME) ;
. . .
END ^
Возможны любые виды преобразований. Предположим, мы хотим получить количество элементов (MEMBERSHIP_NUM), собранное из MEMBER_TYPE, за которым следует строка из десяти цифр, заполненная слева нулями и полученная из сгенерированного первичного ключа таблицы MEMBER. С помощью автоматической генерации в триггере BEFORE INSERT мы можем это осуществить[123]:

