Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык SQL программирование Ред.doc
Скачиваний:
10
Добавлен:
26.08.2019
Размер:
702.46 Кб
Скачать

Триггеры

Microsoft SQL Server 2005 предоставляет два механизма реализации бизнес-правил и целостности данных: ограничения и триггеры.

Триггером называют хранимую процедуру особого типа, которая автоматически выполняется при возникновении языкового события. SQL Server поддерживает два основных типа триггеров: DML-триггеры и DDL-триггеры.

DDL-триггеры впервые появились в SQL Server 2005. Они выполняются при возникновении событий языка определения данных (DDL) на сервере или в базе данных.

DML-триггеры выполняются при возникновении событий языка обработки данных (DML) в базе данных. DML-триггеры могут обращаться к другим таблицам и содержать сложные инструкции Transact-SQL.

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

Триггеры DDL и триггеры DML используются для решения разных задач.

Триггеры DDL создаются для инструкций CREATE, ALTER, DROP и других инструкций DDL. Используют их для выполнения административных задач и гарантии соблюдения бизнес-правил, влияющих на базы данных.

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

Триггеры DDL срабатывают только после выполнения соответствующих инструкций DDL языка Transact-SQL, выполняемых в текущей базе данных или на текущем сервере. Область действия триггера зависит от события.

Действие этих триггеров распространяется на все команды одного типа во всей базе данных или на всем сервере.

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

Для триггеров DDL и DML для одной инструкции Transact-SQL можно создать несколько триггеров.

Пример: триггер DDL может быть использован для предотвращения изменения или удаления любой таблицы базы данных.

CREATE TRIGGER safety

ON DATABASE

FOR DROP_TABLE, ALTER_TABLE

AS

PRINT 'You must disable Trigger "safety" to drop or alter tables!'

ROLLBACK;

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

DML-триггеры удобно использовать в следующих случаях:

  • Для каскадных изменений в связанных таблицах базы данных.

  • Для предотвращения случайных или неправильных операций INSERT, UPDATE и DELETE и реализации других более сложных ограничений, чем те, которые определены при помощи ограничения CHECK. В отличие от ограничений CHECK, DML-триггеры могут ссылаться на столбцы других таблиц.

Например,

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

  • Чтобы оценить состояние таблицы до и после изменения данных и предпринять действия на основе этого различия.

  • Несколько DML-триггеров одинакового типа (INSERT, UPDATE или DELETE) для таблицы позволяют предпринять несколько различных действий в ответ на одну инструкцию изменения данных.

Как и триггеры DML, триггеры DDL могут выполнять управляемый код, упакованный в сборку, созданную в среде Microsoft .NET Framework и переданную на SQL Server.

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

Неправильно написанные триггеры могут привести к серьезным проблемам, таким, например, как появление "мертвых" блокировок. Триггеры способны длительное время блокировать множество ресурсов, поэтому следует обратить особое внимание на сведение к минимуму конфликтов доступа.

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

Чтобы создать, изменить или удалить триггеры DML и триггеры DDL, используется похожий синтаксис Transact-SQL, к тому же они имеют и другие похожие характеристики.

Триггеры DDL создаются при помощи инструкции Transact-SQL CREATE TRIGGER для триггеров DDL (Trigger on a CREATE, ALTER, DROP, GRANT, DENY, REVOKE, or UPDATE STATISTICS оператор).

CREATE TRIGGER trigger_name

ON { ALL SERVER | DATABASE }

[ WITH <ddl_trigger_option> [ ,...n ] ]

{ FOR | AFTER } { event_type | event_group } [ ,...n ]

AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }

<ddl_trigger_option> ::=

[ ENCRYPTION ]

[ EXECUTE AS Clause ]

<method_specifier> ::=

assembly_name.class_name.method_name

Триггеры DML создаются при помощи инструкции Transact-SQL CREATE TRIGGER для триггеров DML (Trigger on an INSERT, UPDATE, or DELETE оператор для таблицы или представления).

CREATE TRIGGER [ schema_name . ]trigger_name

ON { table | view }

[ WITH <dml_trigger_option> [ ,...n ] ]

{ FOR | AFTER | INSTEAD OF }

{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }

[ NOT FOR REPLICATION ]

AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }

<dml_trigger_option> ::=

[ ENCRYPTION ]

[ EXECUTE AS Clause ]

<method_specifier> ::=

assembly_name.class_name.method_name

Аргументы:

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

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

trigger_name - имя триггера. Не может начинаться с символов # или ##.

table | view - таблица или представление, в которых выполняется триггер DML, иногда указывается как таблица триггера или представление триггера. На представление может ссылаться только триггер INSTEAD OF. Триггеры DML не могут быть описаны в локальной или глобальной временных таблицах.

DATABASE - применяет область действия триггера DDL к текущей базе данных.

ALL SERVER - применяет область действия триггера DDL или триггера входа к текущему серверу

WITH ENCRYPTION – шифрует текст инструкции CREATE TRIGGER.

EXECUTE AS - указывает контекст безопасности, в котором выполняется триггер. Позволяет управлять учетной записью пользователя, используемой экземпляром SQL Server для проверки разрешений на любые объекты базы данных, ссылаемые триггером.

FOR | AFTER - тип AFTER указывает, что триггер срабатывает только после успешного выполнения всех операций в инструкции SQL, запускаемой триггером. Все каскадные действия и проверки ограничений, на которые имеется ссылка, должны быть успешно завершены, прежде чем триггер сработает.

Если единственным заданным ключевым словом является FOR, аргумент AFTER используется по умолчанию.

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

INSTEAD OF - указывает, что триггер DML срабатывает вместо инструкции SQL, используемой триггером, переопределяя таким образом действия выполняемой инструкции триггера. Аргумент INSTEAD OF не может быть указан для триггеров DDL или триггеров входа.

Триггеры INSTEAD OF не разрешены для обновляемых представлений, использующих параметр WITH CHECK OPTION. Пользователь должен удалить этот параметр при помощи инструкции ALTER VIEW перед определением триггера INSTEAD OF.

{ [ DELETE ] [ , ] [ INSERT ] [ , ] [ UPDATE ] } - определяет инструкции изменения данных, по которым срабатывает триггер DML, если он применяется к таблице или представлению. Необходимо указать как минимум одну инструкцию. В определении триггера разрешены любые их сочетания в любом порядке.

event_type - имя события языка Transact-SQL, которое после выполнения вызывает срабатывание триггера DDL (например, CREATE_PROCEDURE, см. список событий в разделе DDL-события документации).

event_group - имя стандартной группы событий языка Transact-SQL. Триггер DDL срабатывает после возникновения любого события языка Transact-SQL, принадлежащего к группе event_group (см. список группы событий в разделе Группы событий документации).

NOT FOR REPLICATION - указывает, что триггер не может быть выполнен, если агент репликации изменяет таблицу, используемую триггером.

sql_statement - условия и действия триггера. Условия триггера указывают дополнительные критерии, определяющие, какие события — DML, DDL или событие входа — вызывают срабатывание триггера.

Действия триггера, указанные в инструкциях языка Transact-SQL, вступают в силу после попытки использования операции.

Созданные триггеры включены по умолчанию.

Пример: Следующий триггер DML отправляет клиенту сообщение, когда кто-то пытается добавить или изменить данные в таблице Customer.

USE AdventureWorks;

GO

IF OBJECT_ID ('Sales.reminder1', 'TR') IS NOT NULL

DROP TRIGGER Sales.reminder1;

GO

CREATE TRIGGER reminder1

ON Sales.Customer

AFTER INSERT, UPDATE

AS RAISERROR ('Notify Customer Relations', 16, 10);

GO

Примечания:

IF OBJECT_ID ('Sales.reminder1', 'TR') IS NOT NULL

DROP TRIGGER Sales.reminder1; - проверяет наличие триггера с таким именем.

RAISERROR - создает сообщение об ошибке и запускает обработку ошибок для сеанса (см. документацию).

Результат:

Пример:

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

USE PrimerDB2;

GO

IF OBJECT_ID ('reminder1', 'TR') IS NOT NULL

DROP TRIGGER reminder1;

GO

CREATE TRIGGER reminder1

ON Table1

For INSERT

AS RAISERROR ('Сообщение', 16, 10);

GO

Операция:

INSERT INTO Table1 VALUES (6, 50);

Сообщение:

Msg 50000, Level 16, State 10, Procedure reminder1, Line 4

Сообщение

Пример: создается триггер DML, который проверяет уровень кредитоспособности поставщика при попытке добавить новый заказ на покупку в таблицу PurchaseOrderHeader. Для получения сведений о кредитоспособности поставщика требуется ссылка на таблицу Vendor. В случае слишком низкой кредитоспособности выводится соответствующее сообщение, и вставка не производится.

IF OBJECT_ID ('Purchasing.LowCredit','TR') IS NOT NULL

DROP TRIGGER Purchasing.LowCredit;

GO

CREATE TRIGGER LowCredit ON Purchasing.PurchaseOrderHeader

AFTER INSERT

AS

DECLARE @creditrating tinyint,

@vendorid int

SELECT @creditrating = v.CreditRating, @vendorid = p.VendorID

FROM Purchasing.PurchaseOrderHeader AS p

INNER JOIN inserted AS i ON p.PurchaseOrderID =

i.PurchaseOrderID

JOIN Purchasing.Vendor AS v on v.VendorID = i.VendorID

IF @creditrating = 5

BEGIN

RAISERROR ('This vendor''s credit rating is too low to accept new

purchase orders.', 16, 1)

ROLLBACK TRANSACTION

END

GO

Триггер можно изменить оператором ALTER TRIGGER. Синтаксис аналогичен созданию триггера.

Отключение, включение и удаление триггеров.

Если триггер больше не нужен, он может быть отключен или удален.

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

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

Триггеры DML, определенные для таблиц, можно отключать и включать инструкцией ALTER TABLE.

Параметр инструкции ALTER TABLE:

………………………………………..

{ ENABLE | DISABLE } TRIGGER

   { ALL | trigger_name [ ,...n ] }

……………………………………….

Отключение:

DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL }

ON { object_name | DATABASE | ALL SERVER } [ ; ]

Аргументы:

schema_name - имя схемы, которой принадлежит триггер. Для триггеров DDL или триггеров входа аргумент schema_name не задается.

trigger_name - имя триггера, который нужно отключить.

ALL - означает, что все триггеры в области действия предложения ON будут отключены.

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

Пример:

USE AdventureWorks;

GO

DISABLE TRIGGER Person.uAddress ON Person.Address;

GO

Включение:

ENABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL }

ON { object_name | DATABASE | ALL SERVER } [ ; ]

Включает триггер DML, DDL или logon. Включение триггера приводит к его запуску при выполнении любых событий, на которые он изначально был запрограммирован.

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

Чтобы включить триггер DDL или logon (триггеры входа могут срабатывать в ответ на событие LOGON, возникающее при установке пользовательских сеансов) в области сервера (ON ALL SERVER), пользователь должен иметь разрешение CONTROL SERVER для сервера. Чтобы включить триггер DDL в области базы данных (ON DATABASE), пользователь должен, как минимум, иметь разрешение ALTER ANY DATABASE DDL TRIGGER для текущей базы данных.

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

DROP TRIGGER schema_name.trigger_name [ ,...n ] [ ; ] -Trigger on an INSERT, UPDATE, or DELETE statement to a table or view (DML триггер)

DROP TRIGGER trigger_name [ ,...n ]

ON { DATABASE | ALL SERVER }

[ ; ] - Trigger on a CREATE, ALTER, DROP, GRANT, DENY, REVOKE or UPDATE statement (DDL триггер)

Удаляет один или более DML, DDL триггеров из текущей базы данных.

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

Чтобы удалить триггер DML, необходимо разрешение ALTER для таблицы или представления, в которых определен данный триггер.

Чтобы удалить триггер входа или триггер DDL, определенный в области сервера (ON ALL SERVER), для этого сервера требуется разрешение CONTROL SERVER.

Чтобы удалить триггер DDL, определенный в области базы данных (ON DATABASE), необходимо разрешение ALTER ANY DATABASE DDL TRIGGER для текущей базы данных.

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

Инструкции триггеров DML используют две особые таблицы: deleted (удаленные значения) и inserted (вставленные значения). SQL Server 2005 автоматически создает и управляет ими.

Эти временные таблицы, находящиеся в оперативной памяти, используются для проверки результатов изменений данных и для установки условий срабатывания триггеров DML. Нельзя в этих таблицах изменять данные напрямую или выполнять над ними операции языка DDL, например инструкцию CREATE INDEX.

В триггерах DML таблицы inserted и deleted в основном используются для выполнения следующих операций.

  • Расширение ссылочной целостности между таблицами.

  • Вставка или обновление данных в базовых таблицах соответствующего представления.

  • Проверка на ошибки и принятие соответствующих мер в связи с появлением ошибок.

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

В таблице deleted находятся копии строк, с которыми работали инструкции DELETE или UPDATE. При выполнении инструкции DELETE или UPDATE происходит удаление строк из таблицы триггера и их перенос в таблицу deleted.

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

Транзакция обновления аналогична выполнению операции удаления с последующим выполнением операции вставки; сначала старые строки копируются в таблицу deleted, а затем новые строки копируются в таблицу триггера и в таблицу inserted.

Пример использования таблицы deleted в триггере для выполнения бизнес-правил:

Создать триггер для обработки операции удаления записи из таблицы Сделка:

DELETE FROM Сделка WHERE КодСделки=4

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

CREATE TRIGGER Триггер_del

ON Сделка FOR DELETE

AS

IF @@ROWCOUNT=1 -- удалена одна запись

BEGIN

DECLARE @y INT,@x INT

--определяется код и количество товара из

--удаленной из таблицы Сделка записи

SELECT @y=КодТовара, @x=Количество

FROM deleted

--в таблице Склад корректируется количество товара

UPDATE Склад

SET Остаток=Остаток-@x

WHERE КодТовара=@y

END

Пример использования таблицы inserted в триггере для выполнения бизнес-правил:

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

Команда вставки записи в таблицу Сделка:

INSERT INTO Сделка

VALUES (3,1,-299,'01/08/2002')

Создаваемый триггер должен отреагировать на ее выполнение следующим образом: необходимо отменить команду, если в таблице Склад величина остатка товара оказалась меньше продаваемого количества товара с введенным кодом (в примере код товара=3).

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

CREATE TRIGGER Триггер_ins

ON Сделка FOR INSERT

AS

IF @@ROWCOUNT=1--Возвращает число строк, затронутых при выполнении последней инструкции.

BEGIN

IF NOT EXISTS (SELECT *

FROM inserted

WHERE -inserted.количество<= (SELECT

Склад.Остаток

FROM Склад,Сделка

WHERE Склад.КодТовара=

Сделка.КодТовара))

BEGIN

ROLLBACK TRAN

PRINT

'Отмена поставки: товара на складе нет'

END

END

Пример: поддержка ссылочной целостности для таблиц employee и works_on (если в таблице inserted номер служащего (emp_no) не совпадает с номером служащего в таблице employee, то изменение не выполняется – не может быть вставлен служащий, номер которого не существует).

USE sample;

GO

CREATE TRIGGER workson_integrity

  ON works_on AFTER INSERT, UPDATE

  AS

IF UPDATE(emp_no)

     BEGIN      IF (SELECT employee.emp_no

         FROM employee, inserted          WHERE employee.emp_no = inserted.emp_no) IS NULL

       BEGIN

       ROLLBACK TRANSACTION

       PRINT 'No insertion/modification of the row'

       END

     ELSE PRINT 'The row inserted/modified'

     END

1 @@VERSION - Возвращает информацию о версии, архитектуре процессора, дате сборки и операционной системе текущего экземпляра SQL Server.

2 COALESCE - возвращает первое выражение из списка аргументов, не равное NULL.

Синтаксис:

COALESCE ( expression [ ,...n ] )

85

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]