Что такое триггеры в sql
Перейти к содержимому

Что такое триггеры в sql

  • автор:

Триггеры

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

Формальное определение триггера:

CREATE TRIGGER имя_триггера ON  [INSERT | UPDATE | DELETE] AS выражения_sql

Для создания триггера применяется выражение CREATE TRIGGER , после которого идет имя триггера. Как правило, имя триггера отражает тип операций и имя таблицы, над которой производится операция.

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

Затем устанавливается тип триггера. Мы можем использовать один из двух типов:

  • AFTER : выполняется после выполнения действия. Определяется только для таблиц.
  • INSTEAD OF : выполняется вместо действия (то есть по сути действие — добавление, изменение или удаление — вообще не выполняется). Определяется для таблиц и представлений

После типа триггера идет указание операции, для которой определяется триггер: INSERT , UPDATE или DELETE .

Для триггера AFTER можно применять сразу для нескольких действий, например, UPDATE и INSERT. В этом случае операции указываются через запятую. Для триггера INSTEAD OF можно определить только одно действие.

И затем после слова AS идет набор выражений SQL, которые собственно и составляют тело триггера.

Создадим триггер. Допустим, у нас есть база данных productsdb со следующим определением:

CREATE DATABASE productdb; GO USE productdb; CREATE TABLE Products ( Id INT IDENTITY PRIMARY KEY, ProductName NVARCHAR(30) NOT NULL, Manufacturer NVARCHAR(20) NOT NULL, ProductCount INT DEFAULT 0, Price MONEY NOT NULL );

Определим триггер, который будет срабатывать при добавлении и обновлении данных:

USE productdb; GO CREATE TRIGGER Products_INSERT_UPDATE ON Products AFTER INSERT, UPDATE AS UPDATE Products SET Price = Price + Price * 0.38 WHERE Id FROM inserted)

Допустим, в таблице Products хранятся данные о товарах. Но цена товара нередко содержит различные надбавки типа налога на добавленную стоимость, налога на добавленную коррупцию и так далее. Человек, добавляющий данные, может не знать все эти тонкости с налоговой базой, и он определяет чистую цену. С помощью триггера мы можем поправить цену товара на некоторую величину.

Таким образом, триггер будет срабатывать при любой операции INSERT или UPDATE над таблицей Products. Сам триггер будет изменять цену товара, а для получения того товара, который был добавлен или изменен, находим этот товар по Id. Но какое значение должен иметь Id такой товар? Дело в том, что при добавлении или изменении данные сохраняются в промежуточную таблицу inserted. Она создается автоматически. И из нее мы можем получить данные о добавленных/измененных товарах.

И после добавления товара в таблицу Products в реальности товар будет иметь несколько большую цену, чем та, которая была определена при добавлении:

Триггеры в MS SQL Server

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

Для удаления триггера необходимо применить команду DROP TRIGGER :

DROP TRIGGER Products_INSERT_UPDATE

Отключение триггера

Бывает, что мы хотим приостановить действие триггера, но удалять его полностью не хотим. В этом случае его можно временно отключить с помощью команды DISABLE TRIGGER :

DISABLE TRIGGER Products_INSERT_UPDATE ON Products

А когда триггер понадобится, его можно включить с помощью команды ENABLE TRIGGER :

ENABLE TRIGGER Products_INSERT_UPDATE ON Products

SQL-Ex blog

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

Что такое триггер SQL Server?

Триггер SQL Server — это часть процедурного кода, как и хранимая процедура, но который выполняется только при наступлении определенного события. Имеются различные типы событий, которые могут вызвать срабатывание триггера. Например, вставка строки в таблицу, изменение структуры таблицы или авторизация пользователя в экземпляре SQL Server.

  • Пользователь не может выполнить триггеры вручную.
  • Триггеры не принимают параметры.
  • Вы не можете зафиксировать или откатить транзакцию внутри триггера.

Классы триггеров SQL Server

  • Триггеры DDL (язык определения данных). Этот класс триггеров срабатывает на событиях, которые изменяют структуру (типа создания, модификации или удаления таблицы), или на определенных событиях, относящихся к серверу, например, событиях изменения безопасности или обновления статистики.
  • Триггеры DML (язык модификации данных). Это наиболее часто используемый класс событий. Это события, которые вызывают срабатывание триггера при модификации данных; это может быть оператор insert, update или delete, применяемый к таблице или представлению.
  • FOR или AFTER [INSERT, UPDATE, DELETE]: Эти типы триггеров выполняются после завершения выполнения оператора, вызвавшего срабатывание триггера (insert, update или delete).
  • INSTEAD OF [INSERT, UPDATE, DELETE]: в отличие от типа FOR (AFTER) триггеры INSTEAD OF выполняются вместо оператора, вызвавшего срабатывание триггера. Другими словами, этот тип триггера заменяет вызвавший его оператор. Это очень полезно в случаях, когда вам нужно обеспечить ссылочную целостность между базами данных.

Почему триггеры важны?

Одной из фундаментальных характеристик реляционных баз данных является согласованность данных. Это означает, что информация, хранимая в базе данных должна быть согласована все время для каждой сессии и каждой транзакции. Способ, которым ядро реляционной системы баз данных типа SQL Server обеспечивает согласованность, заключается во введении ограничений, как-то: первичные и внешние ключи. Но иногда этого оказывается недостаточно.

В SQL Server нет возможности обеспечить ссылочную целостность между двумя таблицами посредством внешних ключей, если эти таблицы находятся в разных базах данных или на разных серверах. В таких случаях можно применить только один способ — использование триггеров.

Как узнать, какие строки были обновлены, вставлены или удалены, используя триггер DML в SQL Server?

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

Следует иметь в виду, что таблицы inserted и deleted не всегда доступны вместе (т.е. вы можете иметь таблицу inserted, но не иметь таблицы deleted, и наоборот). Вы можете найти больше информации об этих таблицах в следующей статье.

Синтаксис триггера DML в SQL Server

Вот базовый синтаксис команды создания триггера CREATE TRIGGER.

CREATE TRIGGER trigger_name
ON < Table name or view name >
[ WITH ]
< FOR | AFTER | INSTEAD OF >

В следующей таблице описывается каждый из аргументов синтаксиса CREATE TRIGGER.

Сценарии использования триггеров в SQL Server

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

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

То же самое имеет место, когда вы хотите обеспечить соблюдение бизнес-правил с помощью хранимой процедуры. Если кто-то модифицирует данные в базовой таблице извне приложения, у вас может возникнуть проблема, поскольку согласованность данных в этом случае не будет гарантирована. Чтобы избежать подобных проблем, вы могли бы обеспечить доступ к данным в таблице только посредством хранимой процедуры.

Простой триггер SQL Server DML

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

Сначала мы должны создать таблицу Employees.

CREATE TABLE Employees 
(
EmployeeID integer NOT NULL IDENTITY(1, 1) ,
EmployeeName VARCHAR(50) ,
EmployeeAddress VARCHAR(50) ,
MonthSalary NUMERIC(10, 2)
PRIMARY KEY CLUSTERED (EmployeeID)
)
GO

Затем мы должны создать таблицу EmployeesAudit для хранения записей аудита. Эта таблица имеет ту же структуру, что и таблица Employees, плюс включает столбец AuditId в качестве первичного ключа, ModifiedDate для хранения даты модификации, ModifiedBy для того, чтобы мы могли узнать, кто модифицировал таблицу Employees, и, наконец, Operation, где будет указываться операция DML, которая сгенерировала запись аудита, одной из трех букв ( I для вставки, U для обновления и D для удаления).

CREATE TABLE EmployeesAudit 
(
AuditID INTEGER NOT NULL IDENTITY(1, 1) ,
EmployeeID INTEGER ,
EmployeeName VARCHAR(50) ,
EmployeeAddress VARCHAR(50) ,
MonthSalary NUMERIC(10, 2) ,
ModifiedBy VARCHAR(128) ,
ModifiedDate DATETIME ,
Operation CHAR(1)
PRIMARY KEY CLUSTERED ( AuditID )
)
GO

Чтобы протестировать триггер, нам потребуется добавить некоторые данные в таблицу Employees.

INSERT INTO dbo.Employees 
( EmployeeName ,
EmployeeAddress ,
MonthSalary
)
SELECT 'Mark Smith', 'Ocean Dr 1234', 10000
UNION ALL
SELECT 'Joe Wright', 'Evergreen 1234', 10000
UNION ALL
SELECT 'John Doe', 'International Dr 1234', 10000
UNION ALL
SELECT 'Peter Rodriguez', '74 Street 1234', 10000
GO

Теперь, когда мы имеем все для тестирования, пора создать наш триггер Посмотрите код ниже.

CREATE TRIGGER TR_Audit_Employees ON dbo.Employees 
FOR INSERT, UPDATE, DELETE
AS
DECLARE @login_name VARCHAR(128)
SELECT @login_name = login_name
FROM sys.dm_exec_sessions
WHERE session_id = @@SPID
IF EXISTS ( SELECT 0 FROM Deleted )
BEGIN
IF EXISTS ( SELECT 0 FROM Inserted )
BEGIN
INSERT INTO dbo.EmployeesAudit
( EmployeeID ,
EmployeeName ,
EmployeeAddress ,
MonthSalary ,
ModifiedBy ,
ModifiedDate ,
Operation
)
SELECT D.EmployeeID ,
D.EmployeeName ,
D.EmployeeAddress ,
D.MonthSalary ,
@login_name ,
GETDATE() ,
'U'
FROM Deleted D
END
ELSE
BEGIN
INSERT INTO dbo.EmployeesAudit
( EmployeeID ,
EmployeeName ,
EmployeeAddress ,
MonthSalary ,
ModifiedBy ,
ModifiedDate ,
Operation
)
SELECT D.EmployeeID ,
D.EmployeeName ,
D.EmployeeAddress ,
D.MonthSalary ,
@login_name ,
GETDATE() ,
'D'
FROM Deleted D
END
END
ELSE
BEGIN
INSERT INTO dbo.EmployeesAudit
( EmployeeID ,
EmployeeName ,
EmployeeAddress ,
MonthSalary ,
ModifiedBy ,
ModifiedDate ,
Operation
)
SELECT I.EmployeeID ,
I.EmployeeName ,
I.EmployeeAddress ,
I.MonthSalary ,
@login_name ,
GETDATE() ,
'I'
FROM Inserted I
END
GO

В начале код содержит получение пользователя, который модифицирует таблицу Employees, обращаясь к динамическому административному представлению sys.dm_exec_sessions для получения сессии по текущему
ИД сессии (SPID). Потом триггер вставляет одну запись в таблицу EmployeesAudit для каждой вставленной, обновленной или удаленной записи в таблице Employees, а так же текущее время и операцию DML, которая вызвала срабатывание триггера.

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

Первый из этих запросов выполняет обновление.

BEGIN TRANSACTION 
SELECT *
FROM dbo.Employees
WHERE EmployeeID = 1
UPDATE Employees
SET EmployeeName = 'zzz'
WHERE EmployeeID = 1
SELECT *
FROM dbo.Employees
WHERE EmployeeID = 1
SELECT *
FROM dbo.EmployeesAudit
ROLLBACK TRANSACTION

На следующем скриншоте вы увидите обновленную запись в таблице Employees и новую запись таблице EmployeesAudit, которая отслеживает операцию DML в таблице Employees.

Второй запрос вставляет две строки в таблицу Employees.

BEGIN TRANSACTION 
INSERT INTO dbo.Employees
( EmployeeName ,
EmployeeAddress ,
MonthSalary
)
SELECT 'zz' ,
'dsda' ,
10000
UNION ALL
SELECT 'Markus Rubius' ,
'dsda' ,
6000
SELECT *
FROM dbo.Employees
SELECT *
FROM dbo.EmployeesAudit
ROLLBACK TRANSACTION

На скриншоте ниже вы можете увдеть две вставленные записи в таблице Employees и соответствующие записи аудита в таблице EmployeesAudit.

Наконец, третий запрос — оператор удаления из таблицы Employees.

BEGIN TRANSACTION 
SELECT *
FROM dbo.Employees
WHERE EmployeeID = 1
DELETE FROM dbo.Employees
WHERE EmployeeID = 1
SELECT *
FROM dbo.EmployeesAudit
SELECT *
FROM dbo.Employees
WHERE EmployeeID = 1
ROLLBACK TRANSACTION

На скриншоте видно удаление строки из таблицы Employees и соответствующую запись аудита в таблице EmployeesAudit.

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Автор не разрешил комментировать эту запись

Изучение SQL: триггеры

Сегодня на работе была задача по созданию триггеров на таблицу БД.
Суть заключалась в том, что надо сделать механизм, при котором update/insert в одну таблицу, переносил данные в другую таблицу, а предыдущую удалял.

Так как я раньше не работал с триггерами, пришлось немного почитать и сделать для себя эту заметку.

Типы триггеров.

  1. AFTER — выполняется после выполнения действия. Определяется только для таблиц. Можно определять несколько действий через запятую.
  2. INSTEAD OF — выполняется вместо действия (то есть по сути действие — добавление, изменение или удаление — вообще не выполняется). Определяется для таблиц и представлений. Можно определять только одно действие.

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

CREATE TRIGGER User_Insert_Update_TR ON Users AFTER INSERT, UPDATE -- сработает как для INSERT так и для UPDATE скриптов. AS BEGIN INSERT UsersLog (UserId) SELECT Id FROM inserted END

Управление триггером

DROP TRIGGER User_Insert_Update_TR
DISABLE TRIGGER User_Insert_Update_TR ON Users
ENABLE TRIGGER User_Insert_Update_TR ON Users

Работа со значениями запроса

Внутри каждого триггера можно работать с данными, которые изменяет тот или иной триггер.

  1. Добавление — виртуальная табличка INSERTED.
  2. Удаление — виртуальная табличка DELETED.
  3. Изменение — содержит 2 таблички.
    INSERTED хранит строки после обновления.
    DELETED до обновления.

INSTEAD OF

Данный тип триггеров работает вместо операций с данными. Также его можно применять не только для таблиц но и для представлений.

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

CREATE TRIGGER User_Delete_TR ON Users INSTED OF DELETE AS BEGIN UPDATE Users SET IsActive = 0 WHERE Id FROM deleted) END

Триггеры в SQL

Триггеры в SQL

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

Общие сведения

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

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

Напомню, что мы работаем в MySQL. Триггеры создаются также, как и хранимые процедуры в SQL. Либо во вкладке SQL с помощью кода, либо с помощью графического редактора во вкладке триггеры. Оператор для создания следующий:

CREATE TRIGGER name_trigger
  • BEFORE INSERT
  • BEFORE UPDATE
  • BEFORE DELETE
  • AFTER INSERT
  • AFTER UPDATE
  • AFTER DELETE

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

Пример работы в SQL

Если вы не знакомы со структурой нашей БД, то советуем почитать предыдущие уроки.

Рассмотрим тестовую задачу, которая покажет возможности триггеров. Предположим, что в таблице orders нам нужно поменять цену (поле amt), а новое значение, которое мы введем, увеличить еще на 20%. Задача бывает полезна, когда нужно сделать наценку на товар.

Чтобы нам не высчитывать 20% вручную от новой цены — создадим триггер. Он автоматически будет увеличивать новую цену на 20%.
Вот код создания такого триггера:

DELIMITER // CREATE TRIGGER Before_Update_amt BEFORE UPDATE ON orders FOR EACH ROW BEGIN SET NEW.amt = NEW.amt * 1.2; END // DELIMITER ;

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

Отметим также ключевого слово NEW — это то значение, которое должно было попасть в таблицу, но мы создали триггер и теперь это значение еще увеличивается на 20%.

Следующий момент — цикл FOR EACH ROW. Он необходим потому, что одновременно может изменяться не одно значение, а несколько строк. Вот, для каждой измененной строчки мы и увеличиваем значение на 20%.

Триггер на взаимодействие таблиц

Рассмотрим еще одну задачу: у нас есть продавец (в таблице salespeople), и его продажи отражены в таблицы orders. Представим теперь, что продавец увольняется и все его продажи тоже следует удалить. Если таких продаж много, то легче всего воспользоваться триггером.

DELIMITER // CREATE TRIGGER After_Delete_salespeople AFTER DELETE ON salespeople FOR EACH ROW BEGIN DELETE FROM orders WHERE orders.snum = OLD.snum; END // DELIMITER ;

Итак, после удаления продавца из salespeople берется его уникальный номер snum — он записан в коде как OLD.snum. Затем, по этому уникальному номеру удаляются все строчки из таблицы orders.

Можете проверить этот код, или его аналог. После удаления продавца триггер в SQL удаляет все записи из таблицы orders.

Ключевые слова OLD и NEW

На всякий случай, еще раз разберем употребление этих ключевых слов.

NEW — это значение, которое может появиться только после обновления или вставки данных. Оно содержит то значение, которое должно появиться в таблице. С помощью триггера можно изменить это новое значение, как было сделано в первом примере этой статьи.

OLD — это значение, которое уже было в таблице, либо перед удалением, либо перед обновлением. Обращаться к этому значению имеет смысл, чтобы получить id, и по этому id в другой таблице удалить связанные записи. Так было сделано во втором примере.

Заключение

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

Поделиться ссылкой:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *