Триггеры, объявление и назначения триггеров в SQL. Создание и использование триггеров

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

Триггер всегда работает с текущей записью и реализует конкретное действие.

Триггеры могут выполняться до наступления события (параметр BEFORE) или после наступления события (параметр AFTER).

Триггеры различают по направлению действия:

  • INSERT - на добавление записи;
  • UPDATE - на редактирование записи;
  • DELETE - на удаление записи.

Триггер создается для конкретной таблицы и принадлежит ей. Если таблица имеет несколько триггеров одного направления действия, то время их срабатывания определяется в первую очередь параметрами BEFORE и AFTER , а при одинаковом значении параметра наступления события - параметром POSITION с указанием номера (порядка) срабатывания триггера.

При работе с триггерами следует иметь в виду, что:

  • при откате транзакций откатываются все изменения, сделанные триггерами;
  • легко реализуются каскадные изменения и каскадные удаления в дочерних таблицах;
  • изменения, внесенные в тело триггера, автоматически работают для каждого приложения клиента, т. е. нет необходимости сделанные изменения доводить до каждого пользователя.

Создание триггера производится по правилам создания хранимых процедур, хотя имеются некоторые особенности.

Создание триггера

Для создания триггера используется оператор CREATE TRIGGER.

Формат оператора

CREATE TRIGGER FOR

[ ACTIVE | INACTIVE ]

[ BEFORE |AFTER]

[ INSERT | UPDATE DELETE ]

[ POSITION ]

Назначение опций:

ACTIVE - триггер активен, т. е. при обращении к указанной таблице выполняется процедура, записанная в стеле триггерам

INACTIVE - триггер пассивен, т. е. триггер создан и хранится на сервере, но при обращении к указанной таблице стело триггера> не выполняется;

BEFORE - до наступления события;

AFTER - определяет время срабатывания после наступления события;

INSERT - определяет для триггера событие добавления записи в таблицу;

UPDATE - определяет для триггера событие редактирования записи в таблице;

DELETE - определяет для триггера событие удаления записи из таблицы;

POSITION - определяет номер (позицию) срабатывания триггера внутри определенного события срабатывания (BEFORE или AFTER).

Для описания процедуры стело триггера> используются те же операторы и конструкции, которые используются при создании хранимой процедуры. В заголовке триггера определяют его активность, событие срабатывания, действие, на которое он реагирует, и, при необходимости, позицию срабатывания триггера.

При написании стела триггера> дополнительно можно использовать ключевые слова OLD (до события) и NEW (после события) с последующим указанием имени поля.

Так как в удаленной базе данных все изменения в таблицах (добавление, редактирование и удаление записи) производятся в выборках (в оперативной памяти), то, например, при изменении значения поля можно обратиться как к старому (до изменения) значению поля - ОЬО.симя поля>, так и к новому (после изменения) значению поля - NEW-симя полях Если в указанное поле изменение не вносилось, то ОЬО.симя поля> будет равно NEW.chmb полях

Пример 6.10. Создание триггера.

CREATE TRIGGER T_COMPCODE FOR COMPOSERS

ACTIVE BEFORE INSERT POSITION 0

new.code_composer=gen_id(g_composers, 1); if(COMPOSERS.data born is not null) then begin

new.actuallyage = (CAST("NOW" AS DATE)-COMPOSERS.data_born)/365; if(COMPOSERS.data day is not null) then COM POSERS.age =(COMPOSERS.data_day-COMPOSERS. data born) /365; else new.age=null; end

Триггер срабатывает до наступления события добавления новой записи и вычисляет возраст композитора. Вычисленный возраст записывает в поле «actually_age ».

Изменение триггера

Для изменения триггера используется команда ALTER TRIGGER , имеющая аналогичный формат и аналогичный принцип работы, что и команда ALTER PROCEDURE для изменения тела хранимой процедуры.

Формат команды

ALTER TRIGGER FOR [ ACTIVE I INACTIVE

BEFORE I AFTER

INSERT I UPDATE DELETE

[ POSITION 1

После выполнения оператора ALTER TRIGGER старое определение триггера заменяется новым определением. Старое определение триггера восстановить нельзя.

Пример 6.11. Редактирование триггера.

ALTER TRIGGER T_COMPCODE FOR COMPOSERS ACTIVE BEFORE INSERT POSITION 5 AS

new.code_composer=gen_id(g_composers, 1); if(COMPOSERS.data_born is not null) then begin

new.actually_age = (CAST("NOW" AS DATE)-COMPOSERS.data_born)/365; if(COM POSERS.dataday is not null) then COM POSERS.age =

(COMPOSERS.data_day-COMPOSERS.data born) /365; else new.age=null; end

else begin new.age=null; new.actually_age=null; end end

В триггер, созданный в примере 6.10, внесено изменение: задана новая позиция (POSITION ) срабатывания триггера - 5.

Удаление триггера

Для удаления триггера используют команду

Пример 6.12. Удаление триггера.

DROP TRIGGER T_COMPCODE

Восстановить удаленный триггер нельзя.

Использование триггера в каскадных воздействиях

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

Пример 6.13. Каскадное удаление записей.

При удалении фамилии из родительской таблицы ГАМ необходимо удалить соответствующие фамилии (по ключам фами-

лии) во всех дочерних таблицах (в примере таблицы AUTHOR и BOOK).

CREATE TRIGGER DEL FAM FOR FAM ACTIVE

DELETE FROM AUTHOR

WHERE FAM.KEYFAM = AUTHOR. KEYFAM; DELETE FROM BOOK

WHERE FAM.KEY FAM = BOOK.KEY FAM;

Пример 6.14. Каскадное редактирование записей.

При изменении значения ключевого поля (KEY FAM) в родительской таблице FAM необходимо изменить соответствующие значения внешних ключей во всех дочерних таблицах (в примере таблицы AUTHOR и BOOK).

CREATE TRIGGER UPD FAM FOR FAM ACTIVE

BEFORE UPDATE AS

IF (OLD.KEYFAM NEW.KEY FAM) THEN BEGIN

UPDATE AUTHOR SET KEY FAM = NEW.KEY FAM

WHERE KEY FAM - OLD.KEY FAM; UPDATE BOOK SET KEYFAM - N EW. KEYFAM

WHERE KEY FAM = OLD.KEY FAM;

Особенности использования каскадных воздействий:

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

Обеспечение достоверности данных с помощью триггера

Так как одна таблица может иметь несколько триггеров на одно событие (добавление, редактирование или удаление записи), то имеется возможность обеспечить достоверность вводимых в таблицу данных. Для создания триггера по обеспечению достоверности данных дополнительно используют операторы и ключевые слова.

а. Обеспечение уникальности значения поля

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

Пример 6.15. Заполнение поля первичного ключа.

Написать триггер по добавлению уникального значения первичного ключа KEYFAM. Генератор GFAM уже создан.

CREATE TRIGGER К РАМ FOR FAM

N EW. KEYFAM = GEN_ID(G_FAM, 1);

Пример 6.16. Заполнение информационного поля.

CREATE TRIGGER TCOMPDATE FOR COMPOSERS

ACTIVE BEFORE UPDATE POSITION 0

if(COMPOSERS.data born is not null) then begin

new.actually_age = (CAST("NOW" AS

DATE)-COMPOSERS.data_born)/365; if(COMPOSERS.data day is not null) then COM POSERS.age =

(COM POSERS.data_day-COMPOSERS.data_born)/365; else new.age=null; end

else begin new.age=null; new.actually_age=null; end

В данном примере вычисляется возраст человека и заполняется поле actually age.

Ведение журнала аудита с помощью триггера

В удаленных базах данных особый интерес представляет ведение журнала изменений таблиц базы данных с целью определения источника недостоверных данных. При ведении журнала изменений в специальной таблице фиксируется:

  • выполненное действие над таблицей;
  • новое значение поля;
  • старое значение поля;
  • дата внесения изменения;
  • фамилия, имя и отчество пользователя (USER NAME );
  • номер (имя) рабочей станции.

Пример 6.17. Автоматическое заполнение журнала аудита.

CREATE TRIGGER AFTJNS_DOGS FOR DOGS ACTIVE AFTER INSERT POSITION 0 AS begin

insert into log (act, table_name,record_id) values("INSERT","DOGS",DOGS. ID); end

CREATE TRIGGER AFT_UPD_DOGS FOR DOGS ACTIVE AFTER UPDATE POSITION 0 AS begin

insert into log (act,table_name,record_id) values(’UPDATE’,"DOGS’,DOGS.ID); end

CREATE TRIGGER AFT DEL DOGS FOR DOGS ACTIVE AFTER DELETE POSITION 0 AS

insert into log (act,table_name,record_id) values(’DELETE","DOGS’,DOGS.ID); end

В этом примере для таблицы DOGS созданы три триггера (по одному на каждое событие INSERT, UPDATE и DELETE). Каждый из триггеров добавляет в таблицу аудита log одну строку, которая содержит поля «выполненное действие», «имя таблицы» и «номер записи». При желании количество полей в таблице аудита можно увеличить.

Триггер – это подпрограмма, похожая на процедуру БД, автоматически вызываемая СУБД при изменении, удалении или добавлении записи в таблице. К триггерам невозможно обратиться из программы, передать им параметры или получить от них результат. Наиболее часто триггеры применяются для поддержания ссылочной целостности и каскадных операций в БД. Ссылочные спецификации, определяющие каскадные действия при удалении и обновлении и создаваемые при объявлении таблиц, также реализуются через триггеры, однако текст этих триггеров не редактируется.

Назначение триггеров

Предотвращение изменения (например, предотвратить счета от изменений после того как они разосланы).
. Журналирование изменения (например, хранить копии старых данных).
. Аудит изменений (например, вести лог пользователей и ролей, участвующих в изменениях).
. Фиксация изменений (например, обеспечить, чтобы все изменения датировались по часам сервера, а не клиента).
. Реализация бизнес-правил.
. Репликация данных (например, хранить записи всех изменений, которые будут отправлены в другой базе данных более поздней версии).
. Повышение производительности (например, обновление сальдо после каждой детали сделки, для ускорения запросов).

Объявление триггеров

CREATE TRIGGER {BEFORE|AFTER } {DELETE|INSERT|UPDATE [OF ]} ON REFERENCING {OLD {[ROW ]|TABLE [AS ] } NEW {ROW|TABLE } [AS ] }] [FOR EACH {STATEMENT|ROW [WHEN ]}]
[BEGIN ATOMIC ]

[END ]

Ключевые слова

. BEFORE|AFTER – время запуска триггера – до | после операции обновления.
. DELETE|INSERT|UPDATE = событие срабатывания триггера.
. FOR EACH ROW – для каждой строки (строчный триггер, тогда и WHEN).
. FOR EACH STATEMENT – для всей команды (действует по умолчанию).
. REFERENCING – позволяет присваивать до 4-х псевдонимов старым и | или новым строкам и | или таблицам, к которым могут обращаться триггера.

Ограничения триггеров

Тело триггера не может содержать операторов:
. Определения, удаления и изменения объектов БД (таблиц, доменов и т.п.)
. Обработки транзакций (COMMIT, ROLLBACK)
. Подключения и отключения к БД (CONNECT, DISCONNECT)

Особенности применения
. Триггер выполняется после применения всех других (декларативны) проверок целостности и целесообразен тогда, когда критерий проверки достаточно сложен. Если декларативные проверки отклоняют операцию обновления, то до выполнения триггеров дело не доходит. Триггер работает в контексте транзакции, а ограничение FK нет.
. Если триггер вызывает дополнительную модификацию своей базовой таблицы, то чаще всего это не приводит к его рекурсивному выполнению, однако это следует уточнять. В СУБД SQL Server 2005 предусмотрена возможность указания рекурсии до 255 уровней с помощью ключевого слова OPTION (MAXRECURSIV 3).
. Триггеры обычно не выполняются при обработке больших двоичных столбцов (BLOB).
. Следует помнить, что всякий раз при обновлении данных СУБД автоматически создает так называемые триггерные виртуальные таблицы, которые в различных СУБД носят разные название. В InterBase и Oracle – Это New и Old. В SQL Server – Inserted и Deleted. Причем при изменении данных создаются обе. Эти таблицы имеют то же количество столбцов, с теми же именами и доменами, что и обновляемая таблица. В СУБД SQL Server 2005 предусмотрена возможность указания таблицы, включая временную, в которую следует вставить данные с помощью ключевого слова OUTPUT Inserted.ID,… INTO @ .
. В ряде СУБД допустимо объявлять триггеры для нескольких действий одновременно. Для реализации разных реакций на различные действия в Oracle предусмотрены предикаты Deleting, Inserting, Updating, возвращающие True для соответствующего вида обновления.
. В СУБД Oracle можно для триггеров Update указать список столбцов (After Update Of), что обеспечит вызов триггера только при изменении значений только этих столбцов.
. Для каждого триггерного события может быть объявлено несколько триггеров (в Oracle 12 триггеров на таблицу) и обычно порядок их запуска определяется порядком создания. В некоторых СУБД, например, InterBase, порядок запуска указывается с помощью дополнительного ключевого слова POSITION . В общем случае считается, что первоначально должны выполняться триггеры для каждой команды, а затем – для каждой строки.
. Триггеры можно встраивать друг в друга. Так SQL Server допускает 32 уровня вложения (с помощью глобальной переменной @@NextLevel можно определить уровень вложения).

Недостатки триггеров

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

Изменение и удаление триггеров

Для удаление триггера используется оператор DROP TRIGGER
. Для изменения триггера используется оператор ALTER TRIGGER …
. Отключение триггеров
В ряде случаев, например, при пакетной загрузке, триггеры требуется отключать. В ряде СУБД предусмотрены соответствующие возможности. В Oracle и SQL Server ключевые слова DISABLE|ENABLE, в InterBase INACTIVE|ACTIVE в операторе ALTER TRIGGER.

Особенности промышленных серверов

1) InterBase/Firebird

CREATE TRIGGER FOR {ACTIVE|INACTIVE } {BEFORE|AFTER } {INSERT|DELETE|UPDATE } [POSITION ]
AS [DECLARE VARIABLE [()]]
BEGIN

END

Пример:

CREATE TRIGGER BF_Del_Cust FOR Customer
ACTIVE BEFORE DELETE POSITION 1 AS
BEGIN
DELETE FROM Orders WHERE Orders.CNum=Customer.CNum;
END;

2) SQL Server

CREATE TRIGGER ON [WITH ENCRYPTION ] {FOR|AFTER|INSTEAD OF } {INSERT|UPDATE|DELETE }
AS

USE B1;
GO
CREATE TRIGGER InUpCust1 ON Customer AFTER INSERT, UPDATE
AS RAISEERROR(‘Изменена таблица Customer’);

Дополнительные виды триггеров

В СУБД Oracle и SQL Server есть возможность создания (замещающих) триггеров для не обновляемых представлений. Для этого предусмотрены ключевые слова INSTEAD OF:

CREATE TRIGGER ON INSTEAD OF INSERT AS …

Можно отслеживать попытки клиента обновлять данные с помощью представлений и выполнять какие-либо действия, обрабатывать не обновляемые представления и т.п.
. В СУБД SQL Server предусмотрен триггер отката, фактически прекращающий все действия с выдачей сообщения:

ROLLBACK TRIGGER

Создание генераторов

Генератор – это хранящаяся в БД программа, выдающая при каждом обращении к ней уникальное число.

Создание генератора:

CREATE GENERATOR <Имя генератора>

Начальное значение задается инструкцией:

SET GENERATOR <Имя генератора> TO <Начальное значение (целое число)>

CREATE GENERATOR GenStore

SET GENERATOR GenStore TO 1

Обращение к созданному генератору выполняется с помощью функции

GEN_ID (<Имя генератора>, <Шаг>)


Триггер – это процедура, которая находится на сервере БД и вызывается автоматически при модификации записей БД, т.е. при изменении столбцов или при их удалении и добавлении. В отличие от хранимых процедур, триггеры нельзя вызывать из приложения клиента, а также передавать им параметры и получать от них результаты.

Создание триггера:

CREATE TRIGGER <> FOR <>

{BEFORE | AFTER}

{UPDATE | INSERT | DELETE}

AS <Тело триггера>

Описатели ACTIVE | INACTIVE определяют активность триггера сразу после его создания. По умолчанию действует ACTIVE.

Описатели BEFORE | AFTER задают момент начала выполнения триггера до или после наступления соответствующего события, связанного с изменением записей.

Описатели UPDATE | INSERT | DELETE определяют, при наступлении какого события вызывается триггер – при редактировании, добавлении или удалении записей.

Для одного события можно создать несколько триггеров, каждый из которых будет автоматически выполнен (если находится в активном состоянии). При наличии нескольких триггеров порядок их вызова (выполнения) определяет число, указанное в операнде POSITION. Триггеры выполняются в порядке возрастания этих чисел.

Удаление триггера:

DROP TRIGGER <Имя триггера>

Изменение триггера:

Для доступа к значениям столбца используются инструкции формата:

OLD.<Имя столбца> - обращается к старому (до внесения изменений) значению столбца,

NEW.<Имя столбца> - обращается к новому (после внесения изменений) значению столбца.

Создание триггера для занесения в ключевой столбец уникальных значений

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

NEW.S_Code = GEN_ID (GenStore, 1);

При добавлении к таблице Store новой записи ключевому столбцу S_Code этой записи автоматически присваивается уникальное значение. Это обеспечивается обращением GEN_ID к генератору GenStore.


Реализация каскадного удаления записей с участием триггера

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

DELETE FROM Cards WHERE Store.S_Code = Cards.C_Code2;

После удаления записи в таблице Store буду автоматически удалены все соответствующие записи в таблице Cards.

Замечание : для таблиц не должны действовать ограничения ссылочной целостности, заданные на физическом уровне.

Обновление столбцов связи (ключевых столбцов) связанных таблиц, заключающееся в том, что при изменении значения столбца связи главной таблицы соответственно изменяются значения столбца связи всех связанных записей подчиненной таблицы.

CREATE TRIGGER ChangeStore FOR Store

IF (OLD.S_Code <> NEW.S_Code)

THEN UPDATE Cards

SET C_Code2 = NEW.S_Code

WHERE C_Code2 = OLD.S_Code;

При изменении столбца S_Code, используемого для связи главной таблицы Store с подчиненной таблицей Cards, автоматически изменяются значения столбца связи C_Code2 соответствующих записей подчиненной таблицы.

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

В SQL Server существуют два вида триггеров:

    Триггеры выполняемые после события, произошедшего с таблицей (Полный аналог процедур событий в Visual Basic);

    Триггеры выполняемые вместо события, происходящего с таблицей. В этом случае событие (добавление, изменение илиудаление записей ) не выполняется, а вместо него выполняются SQL команды заданные внутри триггера.

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

Замечание : Триггеры создаются для конкретной таблицы и выполняются автоматически, если с таблицей, для которой они были созданы, происходит событие (добавление, изменение или удаление записей ).

Для создания триггера на вкладке нового запроса необходимо набрать команду CREATE TRIGGER , имеющую следующийсинтаксис :

CREATE TRIGGER <Имя триггера>

ON <Имя таблицы>

FOR

AS <Команды SQL>

    Имя триггера - это имя создаваемого триггера.

    Имя таблицы - имя таблицы , для которой создаётся триггер.

    Если используется параметр AFTER, то триггер выполняется после события, а если параметр INSTEAD OF, то выполняется вместо события.

    Параметры INSERT, UPDATE и DELETE определяют событие, при котором (или вместо которого) выполняется триггер.

    Параметр WITH ENCRYPTION - предназначен для включения шифрования данных при выполнении триггера .

    Команды SQL - это SQL команды, выполняемые при активизации триггера.

Рассмотрим примеры создания различных триггеров для таблицы "Студенты" .

Пример : Создаёт триггер "Добавление" , выводящий на экран сообщение "Запись добавлена" при добавлении новой записи в таблицу "Студенты"

CREATE TRIGGER Добавление

ON Студенты

FOR AFTER INSERT

AS PRINT "Запись добавлена"

Пример : Создаёт триггер "Изменение" "Запись изменена" при изменении записи в таблице"Студенты"

CREATE TRIGGER Изменение

ON Студенты

FOR AFTER UPDATE

AS PRINT "Запись изменена"

Пример : Создаёт триггер "Удаление" , выводящий на экран с сообщение "Запись удалена" при удалении записи из таблицы"Студенты"

CREATE TRIGGER Удаление

ON Студенты

FOR AFTER DELETE

AS PRINT "Запись удалена"

Пример : В данном примере вместо удаления студента из таблицы "Студенты" выполняется код между BEGIN и END. Он состоит из двух команд DELETE. Первая команда удаляет все записи из таблицы "Оценки" , которые связаны с записями из таблицы "Студенты" . То есть у которых Оценки.[Код студента] равен коду удаляемого студента. Затем из таблицы"Студенты" удаляется сам студент.

CREATE TRIGGER УдалениеСтудента

ON Студенты

INSTEAD OF DELETE

DELETE Оценки

WHERE deleted.[Код студента]=Оценки.[Код студента]

DELETE Студенты

WHERE deleted.[Код студента]=Студенты.[Код студента]

Замечание : Здесь удаляемая запись обозначается служебным словом deleted.

Замечание : Для обеспечения целостности данных триггеры используют обычно вместе с диаграммами, но мы можем применять такие триггеры и без диаграмм, однако мы не можем применять диаграммы без триггеров.