Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.Б.Д / лекции / 14БД.doc
Скачиваний:
35
Добавлен:
30.05.2020
Размер:
104.45 Кб
Скачать

4 Програмування тригера

При виконанні команд додавання, зміни і видалення записів сервер створює дві спеціальні таблиці: inserted і deleted . В них містяться списки рядків, які будуть вставлені або видалені після закінчення транзакції. Структура таблиць inserted і deleted ідентична структурі таблиць, для якої визначається тригер. Для кожного тригера створюється свій комплект таблиць inserted і deleted, тому ніякий інший тригер не зможе дістати до них доступ. Залежно від типу операції, що викликала виконання тригера, вміст таблиць inserted і deleted може бути різним:

  1. команда INSERT – в таблиці inserted містяться всі рядки, які користувач намагається вставити в таблицю; в таблиці deleted не буде жодного рядка; після завершення тригера всі рядки з таблиці inserted перемістяться в початкову таблицю;

  2. команда DELETE – в таблиці deleted міститимуться всі рядки, які користувач спробує видалити; тригер може перевірити кожний рядок і визначити, чи дозволено її видалення; в таблиці inserted не опиниться жодного рядка;

  3. команда UPDATE – при її виконанні в таблиці deleted знаходяться старі значення рядків, які будуть видалені при успішному завершенні тригера. Нові значення рядків містяться в таблиці inserted. Ці рядки додадуться в початкову таблицю після успішного виконання тригера.

Для отримання інформації про кількість рядків, яка буде змінена при успішному завершенні тригера, можна використовувати функцію @@ROWCOUNT; вона повертає кількість рядків, оброблених останньою командою. Слід підкреслити, що тригер запускається не при спробі змінити конкретний рядок, а у момент виконання команди зміни. Одна така команда впливає на безліч рядків, тому тригер повинен обробляти всі ці рядки.

Якщо тригер знайшов, що з 100 рядків, що вставляються, змінних або видаляються, тільки один не задовольняє тим або іншим умовам, то ніякий рядок не буде вставлений, змінений або видалений. Така поведінка обумовлена вимогами транзакції – повинні бути виконані або всі модифікації, або жодної.

Тригер виконується як неявна транзакція, тому усередині тригера допускається використання команд управління транзакціями. Зокрема, при виявленні порушення обмежень цілісності для переривання виконання тригера і відміни всіх змін, які намагався виконати користувач, необхідно використовувати команду ROLLBACK TRANSACTION.

Для отримання списку стовпців, змінених при виконанні команд INSERT або UPDATE, що викликали виконання тригера, можна використовувати функцію COLUMNS_UPDATED(). Вона повертає двійкове число, кожний біт якого, починаючи з молодшим, відповідає одному стовпцю таблиці (в порядку проходження стовпців при створенні таблиці). Якщо біт встановлений в значення "1", то відповідний стовпець був змінений. Крім того, факт зміни стовпця визначає і функція UPDATE (ім’я_колонки).

Для видалення тригера використовується команда

DROP TRIGGER {ім’я_тригера} [,...n]

Приведемо приклади використання тригерів.

Приклад 14.1. Використання тригера для реалізації обмежень на значення. В тій, що додається в таблицю Операція запису кількість проданого товару повинна бути не більше, ніж його залишок з таблиці Склад.

Команда вставки запису в таблицю Операція може бути, наприклад, така:

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.Кількість<=ALL(SELECT

Склад.Залишок

FROM Склад, Операція

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

Операція.КодТовара))

BEGIN

ROLLBACK TRAN

PRINT

'Відміна поставки: товару на складі нма'

END

END

Приклад 14.1. Використання тригера для реалізації обмежень на значення.

Приклад 14.2. Використання тригера для збору статистичних даних. Створити тригер для обробки операції вставки запису в таблицю Операція, наприклад, такої команди:

INSERT INTO Операція

VALUES (3,1,200,'01/08/2002')

поставляється товар з кодом 3 від клієнта з кодом 1 в кількості 200 одиниць.

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

ALTER TRIGGER Триггер_ins

ON Операція FOR INSERT

AS

DECLARE @x INT @y INT

IF @@ROWCOUNT=1

//--в таблицю Операція додається запис про поставку товару

BEGIN

//--кількість проданого товару повинна бути не менше ніж його залишок з таблиці Склад

IF NOT EXISTS(SELECT *

FROM inserted

WHERE -inserted.Кількість< =ALL(SELECT Склад.Залишок

FROM Склад, Операція

WHERE Склад.КодТовара = Операція.КодТовара))

BEGIN

ROLLBACK TRAN

PRINT 'відкат - товару немає '

END

//--якщо запису про поставлений товар ще немає додається відповідний запис в таблицю Склад

IF NOT EXISTS (SELECT *

FROM Склад С, inserted i

WHERE С.КодТовара=i.КодТовара)

INSERT INTO Склад (КодТовара,Залишок)

ELSE

//--якщо запис про товар вже був в таблиці Склад, то визначається код і кількість товару з доданої в таблицю Операція запису

BEGIN

SELECT @y=i.КодТовара @x=i.Кількість

FROM Операція З, inserted i

WHERE С.КодТовара=i.КодТовара

//--і проводиться зміни кількості товару в Таблиці Склад

UPDATE Склад

SET Залишок=Залишок+@x

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

END

END

Приклад 14.2. Використання тригера для збору статистичних даних.

Приклад 14.3. Створити тригер для обробки операції видалення запису з таблиці Операція, наприклад, такої команди:

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

Приклад 14.3. Тригер для обробки операції видалення запису з таблиці

Приклад 14.4. Створити тригер для обробки операції зміни запису в таблиці Операція, наприклад, такою командою:

UPDATE Операція SET Кількість=Кількість-10

WHERE КодТовара=3

у всіх операціях з товаром, що має код, рівний 3, зменшити кількість товару на 10 одиниць.

Вказана команда може привести до зміни відразу декількох записів в таблиці Операція. Тому покажемо, як створити тригер, оброблювальний не один запис. Для кожного зміненого запису необхідно для старого (до зміни) коду товару зменшити залишок товару на складі на величину старої (до зміни) кількості товару і для нового (після зміни) коду товару збільшити його залишок на складі на величину нового (після зміни) значення. Щоб обробити всі змінені записи, введемо курсори, в яких збережемо всі старі (з таблиці deleted) і всі нові значення (з таблиці inserted).

CREATE TRIGGER Триггер_upd

ON Операція FOR UPDATE

AS

DECLARE @x INT @x_old INT @y INT @y_old INT

//-- курсор з новими значеннями

DECLARE CUR1 CURSOR FOR

SELECT КодТовара, Кількість

FROM inserted

//-- курсор із старими значеннями

DECLARE CUR2 CURSOR FOR

SELECT КодТовара, Кількість

FROM deleted

OPEN CUR1

OPEN CUR2

//-- переміщаємося паралельно по обох курсорах

FETCH NEXT FROM CUR1 INTO @x @y

FETCH NEXT FROM CUR2 INTO @x_old @y_old

WHILE @@FETCH_STATUS=0

BEGIN

//--для старого коду товару зменшується його --кількість на складі

UPDATE Склад

SET Залишок = Залишок-@y_old

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

//--для нового коду товару, якщо такого товару ще немає на складі, вводиться новий запис

IF NOT EXISTS (SELECT * FROM Склад

WHERE КодТовара=@x)

INSERT INTO Склад(КодТовара,Залишок)

VALUES (@x,@y)

ELSE

//--інакше для нового коду товару збільшується --його кількість на складі

UPDATE Склад

SET Залишок = Залишок+@y

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

FETCH NEXT FROM CUR1 INTO @x @y

FETCH NEXT FROM CUR2 INTO @x_old @y_old

END

CLOSE CUR1

CLOSE CUR2

DEALLOCATE CUR1

DEALLOCATE CUR2

Приклад 14.4. тригер для обробки операції зміни запису в таблиці

В розглянутому тригері відсутнє порівняння кількості товару при зміні запису про операцію з його залишком на складі.

Приклад 14.5. Поправний цей недолік. Для генерації повідомлення про помилку використовуємо в тілі тригера команду MS SQL Server RAISERROR, аргументами якої є текст повідомлення, рівень серйозності і статус помилки.

ALTER TRIGGER Триггер_upd

ON Операція FOR UPDATE

AS

DECLARE @x INT @x_old INT @y INT

@y_old INT,@o INT

DECLARE CUR1 CURSOR FOR

SELECT КодТовара,Кількість

FROM inserted

DECLARE CUR2 CURSOR FOR

SELECT КодТовара,Кількість

FROM deleted

OPEN CUR1

OPEN CUR2

FETCH NEXT FROM CUR1 INTO @x @y

FETCH NEXT FROM CUR2 INTO @x_old @y_old

WHILE @@FETCH_STATUS=0

BEGIN

SELECT @o=Залишок

FROM Склад

WHERE кодтовара=@x

IF @o<-@y

BEGIN

RAISERROR('откат',16,10)

CLOSE CUR1

CLOSE CUR2

DEALLOCATE CUR1

DEALLOCATE CUR2

ROLLBACK TRAN

RETURN

END

UPDATE Склад

SET Залишок=Залишок-@y_old

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

IF NOT EXISTS (SELECT * FROM Склад

WHERE КодТовара=@x)

INSERT INTO Склад(КодТовара, Залишок)

VALUES (@x,@y)

ELSE

UPDATE Склад

SET Залишок=Залишок+@y

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

FETCH NEXT FROM CUR1 INTO @x @y

FETCH NEXT FROM CUR2 INTO @x_old @y_old

END

CLOSE CUR1

CLOSE CUR2

DEALLOCATE CUR1

DEALLOCATE CUR2

Приклад 14.5. Виправлений варіант тригера для обробки операції зміни запису в таблиці

Приклад 14.6. В прикладі 14.5 відбувається відміна всіх змін при неможливості реалізувати хоча б одне з них. Створимо тригер, що дозволяє відміняти зміну тільки деяких записів і виконувати зміну інших.

В цьому випадку тригер виконується не після зміни записів, а замість команди зміни.

ALTER TRIGGER Триггер_upd

ON Операція INSTEAD UPDATE

AS

DECLARE @k INT @k_old INT

DECLARE @x INT @x_old INT @y INT

DECLARE @y_old INT,@o INT

DECLARE CUR1 CURSOR FOR

SELECT КодСделки, КодТовара, Кількість

FROM inserted

DECLARE CUR2 CURSOR FOR

SELECT КодСделки, КодТовара,Кількість

FROM deleted

OPEN CUR1

OPEN CUR2

FETCH NEXT FROM CUR1 INTO @k,@x @y

FETCH NEXT FROM CUR2 INTO @k_old,@x_old

@y_old

WHILE @@FETCH_STATUS=0

BEGIN

SELECT @o=Залишок

FROM Склад

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

IF @o>=-@y

BEGIN

RAISERROR('изменение',16,10)

UPDATE Операція SET Кількість=@y

КодТовара=@x

WHERE КодСделки=@k

UPDATE Склад

SET Залишок=Залишок-@y_old

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

IF NOT EXISTS (SELECT * FROM Склад

WHERE КодТовара=@x)

INSERT INTO Склад(КодТовара, Залишок)

VALUES (@x,@y)

ELSE

UPDATE Склад

SET Залишок=Залишок+@y

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

END

ELSE

RAISERROR('запис не змінено',16,10)

FETCH NEXT FROM CUR1 INTO @k,@x @y

FETCH NEXT FROM CUR2 INTO @k_old,@x_old

@y_old

END

CLOSE CUR1

CLOSE CUR2

DEALLOCATE CUR1

DEALLOCATE CUR2

Приклад 14.6. Тригер, що дозволяє відміняти зміну тільки деяких записів і виконувати зміну інших.

Контрольні питання

  1. Дайте визачення тригера. В чому полягає його призначення?

  2. Хто може створити тригер? Чому?

  3. Яких переваг використання можна досягти за допомогою тригера?

  4. Наведіть формальний синтаксис створення тригера та поясніть його параметри.

  5. Що таке подія тригера? На що вона впливає?

  6. В чому полягають недоліки тригерів?

  7. Перерахуйте відомі вам типи тригерів.

  8. Що представляє собою AFTER-тригер?

  9. Що представляє собою INSTEAD-тригер?

  10. Яку функцію виконує INSERT TRIGGER?

  11. Яку функцію виконує UPDATE TRIGGER?

  12. Яку функцію виконує DELETE TRIGGER?

  13. В чому полягає призначення таблиць inserted і deleted?

Соседние файлы в папке лекции