
- •Мова адміністрування бд (мабд)
- •Група Data Control Language (dcl)
- •Група Transaction Control Language (tcl)
- •Група Cursor Control Language (ccl)
- •Пр иклади використання операторів адміністрування
- •Створення і ліквідація ролей
- •Передача привілеїв і ролей
- •Уявлення (View)
- •Поняття збереженої процедури
- •Збережені процедури в конкретних середовищах
- •Типи збережених процедур
- •Створення, зміна і видалення збережених процедур
- •Виконання збереженої процедури .
- •6.5. Визначення тригера в стандарті мови sql
- •Реалізація тригерів в середовищі ms sql Server
- •Типи тригерів
- •Програмування тригера
- •6.7. Технології використання sql
- •Поняття інтерактивного sql
- •Утиліта інтерактивного доступу isql субд Sybase sql Anywhere
- •Приклад використання інтерактивного sql в субд mysql
Програмування тригера
При виконанні команд додавання, зміни і видалення записів сервер створює дві спеціальні таблиці: inserted і deleted. У них містяться списки рядків, які будуть вставлені або видалені після закінчення транзакції. Структура таблиць inserted і deleted ідентична структурі таблиць, для якої визначається тригер. Для кожного тригера створюється свій комплект таблиць inserted і deleted, тому ніякий інший тригер не зможе дістати до них доступ. Залежно від типу операції, що викликала виконання тригера вміст таблиць inserted і deleted може бути різним:
команда INSERT - в таблиці inserted містяться всі рядки, які користувач намагається вставити в таблицю; у таблиці deleted не буде жодного рядка; після завершення тригера всі рядки з таблиці inserted перемістяться в початкову таблицю;
команда DELETE - в таблиці deleted міститимуться всі рядки, які користувач спробує видалити; тригер може перевірити кожен рядок і визначити, чи дозволено її видалення; у таблиці inserted не опиниться жодного рядка;
команда UPDATE - при її виконанні в таблиці deleted знаходяться старі значення рядків, які будуть видалені при успішному завершенні тригера. Нові значення рядків містяться в таблиці inserted. Ці рядки додадуться в початкову таблицю після успішного виконання тригера.
Для отримання інформації про кількість рядків, яка буде змінено при успішному завершенні тригера, можна використовувати функцію @@ROWCOUNT\ вона повертає кількість рядків, оброблених останньою командою. Слід підкреслити, що тригер запускається не при спробі змінити конкретний рядок, а у момент виконання команди зміни. Одна така команда впливає на множину рядків, тому тригер повинен обробляти всі ці рядки.
Якщо тригер виявив, що з 100 рядків, що вставляються, змінних або таких, що видаляються, тільки одна не задовольняє тим або іншим умовам, то жодний рядок не буде вставлений, змінений або видалений. Така поведінка обумовлена вимогами транзакції - мають бути виконані або всі модифікації, або жодна.
Тригер виконується неявно як певна транзакція, тому усередині тригера допускається застосування команд управління транзакціями. Зокрема, при виявленні порушення обмежень цілісності для переривання виконання тригера і відміни всіх змін, які намагався виконати користувач, необхідно використовувати команду ROLLBACK TRANSACTION.
Для отримання списку колонок, змінених при виконанні команд INSERT або UPDATE, що викликали виконання тригера, можна використовувати функцію COLUMNSJJP DATED (). Вона повертає двійкове число, кожен біт якого, починаючи з молодшого, відповідає одній колонці таблиці (в порядку проходження колонок при створенні таблиці). Якщо біт встановлений в значення «1», то відповідна колонка бувла змінена. Крім того, факт зміни клонки визначає і функція UPDATE (ім’я колонки). Для видалення тригера використовується команда:
DROP TRIGGER {ім'яjnpuzepa} [,. .п]
Приведемо приклади використання тригерів.
Приклад 6.11. Використання тригера для реалізації обмежень на значення. Наприклад інформаційна система відслідковує транзакції, що відбуваються на складі супермаркету. Кожна транзакція фіксується в таблиці Операція. Бізнес-логіка цієї операції проста: кількість проданого товару не може перевищувати залишок з таблиці Склад. Команда вставки запису в таблицю exam може бути, наприклад, такий:
INSERT INTO Операція
VALUES (3,1-299, '08/01/2009')
Створюваний тригер повинен відреагувати на її виконання таким чином: необхідно відмінній команду, якщо в таблиці Склад величина залишку товару виявилася менше кількості товару, що продавалася, з введеним кодом (у прикладі код товара=3). У записі, що вставляється, кількість товару указується із знаком «+», якщо товар поставляється, і із знаком «-», якщо він продається. Представлений тригер налаштований на обробку тільки одного запису, що додається.
CREAТЕ TRIGGER Тригер_ins
GRANT ROLE ім'я ролі [ON об'єкт] ТО суб'єкт [WITH GRANT OPTION] 195
ШВІ 208
FROM deleted 213
WHERE -inserted.KuibKicmb<=ALL(SELECT Склад.Залишок FROM Склад, Операція
WHERE Склад.КодТовара=Операція. Код Товара))
BEGIN
GRANT ROLE ім'я ролі [ON об'єкт] ТО суб'єкт [WITH GRANT OPTION] 195
ШВІ 208
FROM deleted 213
Приклад 6.12. Використання тригера для збору статистичних даних. Створити тригер для обробки операції вставки запису в таблицю Операція, наприклад, такої команди:
INSERT INTO Операція VALUES (3,1,200, '01/08/2002')
Поставляється товар з кодом 3 від клієнта з кодом 1 в кількості 200 одиниць. При продажі або отриманні товару необхідно відповідним чином змінити кількість його складського запасу. Якщо товару на складі ще немає, необхідно додати відповідний запис в таблицю Склад. Тригер обробляє тільки один рядок, що додається.
ALTER TRIGGER Тригер Jns ON Операція FOR INSERT AS
DECLARE @x INT @y INT IF @@RO WCO UNT= 1
у таблицю Операція додається запис про постачання товару BEGIN
кількість проданого товару повинна бути не менше, ніж його залишок з таблиці Склад
IF NOT EX1STS(SELECT *
FROM inserted
WHERE -inserted.Кількість< =ALL(SELECTСклад.Залишок FROM Склад, Операція WHERE Склад.КодТовара- Операція.КодТовара))
BEGIN
ROLLBACK TRAN PRINT ’відкочування товару нема '
END
Якщо запису про поставлений товар ще немає, додається відповідний запис у таблицю Склад:
IF NOT EXISTS ( SELECT *
FROM Склад C, inserted і WHERE С.КодТовара=і. КодТовара )
INSERT INTO Склад (КодТовара, Залишок)
ELSE
Якщо запис про товар вже був в таблиці Склад, то визначається код і кількість товару із доданої в таблицю Операція запису:
BEGIN
SELECT @у-і. КодТовара, @рс-і. Кількість FROM Операція С, inserted і WHERE С.КодТовара=і.КодТовара і проводить зміни кількості товару в таблиці Склад UPDATE Склад SET Залишок=Залишок+@х WHERE КодТовара=@у END END
Приклад 6.13. Створити тригер для обробки операції видалення запису з таблиці Операція, наприклад, такої команди:
DELETE FROM Операція WHERE КодУгоди=14 Для товару, код якого вказаний при видаленні запису, необхідно відкоригувати його залишок на складі. Тригер обробляє тільки один запис, що видаляється.
CREATE TRIGGER Тригер_del ON Операція FOR DELETE AS
IF @@ROWCOUNT=I - видалений один запис BEGIN DECLARE @y INT,@x 1NT
визначається код і кількість товару з видаленою з таблиці Склад запису
SELECT@у=КодТовара, @х~Кількість
FROM deleted
у таблиці Склад коригується кількість товару UPDATE Склад '
SET Залишок=Залишок-@х WHERE КодТовару-@у END '
Приклад 6.14. Створити тригер для обробки операції зміни запису в таблиці Операція, наприклад, такою командою:
UPDATE Операція SET Кількість =Кількість-І0 WHERE КодТовару=31 у всіх операціях з товаром, що має код, дорівнює 31, зменшити кількість товару на 10 одиниць. Вказана команда може привести до зміни відразу декількох записів в таблиці Операція. Тому покажемо, як створити тригер, що обробляє не один запис. Для кожного зміненого запису необхідно для старого (до зміни) коду товару зменшити залишок товару на складі на величину старої (до зміни) кількості товару і для нового (після зміни) коду товару збільшити його залишок на складі на величину нового (після зміни) значення. Щоб обробити всі змінені записи, введемо курсори, в яких збережемо всі старі (з таблиці deleted) і всі нові значення (з таблиці inserted). Ось тут нам знадобляться оператори групи Cursor Control Language (CCL), зокрема FETCH.
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 CUR 1 INTO @x, @y FETCH NEXT FROM CUR2 INTO @x_old, @y_old WHILE @@FETCH STATUS-0 BEGIN
для старого коду товару зменшується його кількість на складі UPDATE Склад
SET Залишок-Залишок-@у_оІс1 WHERE Код Товару=@x_old для нового коду товару, якщо такого товару ще немає на складі, вводиться новий запис
IF NOT EXISTS (SELECT * FROM Склад WHERE КодТовару=@x)
INSERT INTO Склад(КодТовара,Залишок)
VALUES (@x,@y)
I ELSE
інакше для нового коду товару збільшується його кількість на складі UPDATE Склад SET Залишок=Залишок+@у WHERE КодТовару=@х FETCH NEXT FROM CUR I INTO @x, @y FETCH NEXT FROM CUR2 INTO (cbx old, @y old
END Г , . 7/ ' Л1
CLOSE CURI
CLOSE CUR2
DEALLOCATE CURI
DEALLOCATE CUR2
У розглянутому тригері відсутнє порівняння кількості товару при зміні запису про операцію з його залишком на складі.
Приклад 6.15. Виправлення помилки. Для генерування повідомлення про помилку використовуємо в тілі тригера команду MS SQL Server RAISERROR, аргументами якої є текст повідомлення, рівень серйозності і статус помилки.
ALTER TRIGGER Тригер_upd ON Операція FOR UP DA ТЕ AS
DECLARE @x INT @x_old INT @y INT @y_old I NT, @o INT DECLARE CURI CURSOR FOR SELECT КодТовару, Кількість FROM inserted DECLARE CUR2 CURSOR FOR SELECT КодТовару, Кількість FROM deleted OPEN CURI OPEN CUR2 FETCH NEXT FROM CUR I INTO @x, @y FETCH NEXT FROM CUR2 INTO @x_old, @y_old
WHILE @@FETCH_STA TUS=0 BEGIN
SELECT @о-залишок FROM Склад WHERE кодтовара-@х IF @o<-@y BEGIN
RA ISERROR('omKam16,10)
CLOSE CUR1 CLOSE CUR2 DEALLOCATE CUR1 DEALLOCATE CUR22 ROLLBACK TRAN RETURN END UPDATE Склад SET Залиіиок~Залишок-@у_оШ WHERE KodToeapa=@x_old IF NOT EXISTS (SELECT * FROM Склад WHERE KodToeapa=@x)
INSERT INTO Склад(КодТовара, Залишок)
VALUES (@x,@y)
ELSE UPDATE Склад SET Залишок=Залишок+@у WHERE KodToeapa=@x FETCH NEXT FROM CUR1 INTO @x, @y FETCH NEXT FROM CUR2 INTO @pc_old, @y_old END
CLOSE CUR1 CLOSE CUR2 DEALLOCATE CUR1 DEALLOCATE CUR2