Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
3
Добавлен:
16.07.2022
Размер:
289.64 Кб
Скачать

Лабораторная работа №9

Триггеры, курсоры, транзакции в SQL Server

Цель: работы: получить навыки применения курсоров, использования транзакций, а также работы с триггерами в MS SQL Server.

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

Далее следует краткий конспект теоретического материала.

Теоретические сведения *

Триггеры

Триггер TRIGGER – процедура, автоматически выполняемая при наступлении заданного события (INSERT, UPDATE, DELETE для триггеров языка манипулирования данными (Data

Manipulation Language — DML), и CREATE, ALTER, DROP для языка определения данных (Data

Definition Language — DDL)).

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

Целями использования триггеров обычно являются:

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

-выдача предупреждений о необходимости выполнения некоторых действий при обновлении таблицы;

-накопление аудиторской информации посредством фиксации сведений о внесенных изменениях и тех лицах, которые их выполнили;

-поддержка репликации.

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

Синтаксис:

CREATE TRIGGER имя_триггера

BEFORE | AFTER <триггерное_событие> ON <имя_таблицы>

[REFERENCING <список_старых_или_новых_псевдонимов>]

[FOR EACH { ROW | STATEMENT}] [WHEN(условие_триггера)] <тело_триггера>

ENCRYPTION – тело функции будет недоступно для открытого просмотра

SCHEMABINDING – запрет функции вносить изменения в БД

Кроме того, в MS SQL существуют дополнительные возможности при создании и триггера. В СУБД SQL Server существуют два подкласса триггеров DML: INSTEAD OF (триггер замены операции) и AFTER (триггер, выполняющийся сразу после операции), отличающиеся

своим назначением, моментом выполнения и производимым эффектом (табл. 1).

Синтаксис:

{CREATE | ALTER} TRIGGER имя_триггера

ON {имя_таблицы | имя_представления }

[WITH ENCRYPTION ]

{

{{ FOR | AFTER | INSTEAD OF }

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

[ NOT FOR REPLICATION ] AS sql_оператор[...n]

} |

{FOR | AFTER | INSTEAD OF } { [INSERT] [,] [UPDATE] } [ WITH APPEND ]

[ NOT FOR REPLICATION ] AS

{IF UPDATE(имя_столбца) [ {AND | OR} UPDATE(имя_столбца)] [...n]

|

IF (COLUMNS_UPDATES() {оператор_бит_обработки} бит_маска_изменения) {оператор_бит_сравнения } бит_маска [...n] }

sql_оператор [...n]

}

}

Пример:

Отменить команду INSERT INTO Сделка …, если в таблице Склад величина остатка товара меньше продаваемого количества товара с введенным кодом:

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

Таблица 1. Сравнение характеристик подклассов триггеров DML

Характеристика

Триггер INSTEAD OF

Триггер AFTER

Эффект оператора

Автоматически

Выполняется, если триггер

DML

откатывается

сам не откатит транзакцию

Момент

Перед проверкой ограничений

После выполнения транзакции,

выполнения

первичного и внешнего ключей

но перед ее подтверждением

триггера

 

 

Количество

 

 

возможных

Одно

Несколько

событий таблицы

 

 

Возможность

 

 

применения к

Есть

Отсутствует

представлениям

 

 

Рекурсивное

Отсутствует

Зависит от параметров

срабатывание

настройки СУБД

 

Оператор DML не может повлиять на срабатывание триггера, однако триггер можно временно отключить оператором ALTER TABLE с параметром DISABLE TRIGGER:

ALTER TABLE имя_таблицы DISABLE TRIGGER имя_триггера

Для включения триггера применяется тот же оператор, но с параметром ENABLE

TRIGGER:

ALTER TABLE имя_таблицы ENABLE TRIGGER имя_триггера

Триггер AFTER

Триггер AFTER создается оператором следующего вида:

CREATE TRIGGER имя_триггера ON имя_таблицы

AFTER операция, ...

AS

программный_код_триггера

Созданный триггер выполняется в ответ на событие, возникающее после завершения указанной за ключевым словом AFTER операции добавления (Insert), удаления (Delete) или обновления (Update), но до подтверждения фиксации результатов модификации. Например, триггер, созданный оператором:

CREATE TRIGGER ai_PROFIT_trig ON PROFIT AFTER Insert

AS

PRINT('Добавлена строка');

выводит сообщение «Добавлена строка» при добавлении каждой строки в таблицу PROFIT, в чем можно убедиться, если воспользоваться оператором

INSERT INTO PROFIT (Id, Source, Moneys)

VALUES (9, 'Менеджер', 20000.00)

Предложение AFTER

Предложение AFTER позволяет указать операцию (или операции), приводящие к запуску триггера. Может быть предусмотрен запуск триггера при выполнении оператора INSERT, UPDATE или DELETE либо любого сочетания этих трех операторов, например:

AFTER INSERT, DELETE

или

AFTER UPDATE, INSERT

или

AFTER DELETE

Триггеры, объявляемые с предложением AFTER, могут быть закреплены только за таблицами; закрепление этих триггеров за представлениями не допускается.

Триггеры INSERT

Код любого триггера, который объявлен с ключевыми словами AFTER INSERT, вызывается на выполнение каждый раз, когда кто-либо вставляет новую строку в таблицу, за которой закреплен триггер. Для каждой вставляемой строки СУБД SQL Server создает копию этой новой строки и вставляет ее в специальную таблицу, существующую только в области определения данного триггера. Эта таблица называется INSERTED. Наиболее важная особенность таблицы INSERTED состоит в том, что она сохраняется только до тех пор, пока действует триггер, с которым она связана, т.е. таблица INSERTED существует только с момента запуска триггера и до момента завершения его выполнения.

Триггеры DELETE

Триггеры DELETE действуют аналогично триггерам INSERT, не считая того, что связанная с ними таблица INSERTED пуста, вместо этого копия каждой удаленной строки вставляется в таблицу DELETED. Эта таблица, как и таблица INSERTED, имеет область определения, которая ограничивается исключительно продолжительностью существования триггера.

Триггеры UPDATE

Запуск кода триггера, объявленного с ключевыми словами AFTER UPDATE, происходит при каждом внесении изменения в строку, существующую в таблице. При этом в СУБД SQL Server операция модификации каждой строки трактуется так, как будто удаляется существующая строка и вставляется полностью новая. Триггер, объявленный с ключевыми словами AFTER UPDATE, обслуживается с помощью двух специальных таблиц: и INSERTED, и DELETED, количество строк в которых одинаково.

Виртуальные таблицы Inserted и Deleted

Таблицы INSERTED и DELETED можно рассматривать как представления журнала транзакций, т.е. виртуальные таблицы. Их содержимое для каждого оператора DML в краткой форме отражено в табл.2, которая показывает, что таблица DELETED содержит строки в состоянии до применения оператора DML, а таблица INSERTED — после применения. К этим таблицам можно обращаться только внутри триггера; хранимые процедуры, вызываемые триггером, не имеют доступа к этим таблицам.

Таблица 2. Содержимое виртуальных таблиц Inserted и Deleted

Оператор

 

Виртуальная таблица

Inserted

 

Deleted

 

 

insert

Вставленные строки

 

Пустая

update

Строки базы данных после

 

Строки базы данных до обновления

 

обновления

 

 

 

 

delete

Пустая

 

Строки, подлежащие удалению

В следующем примере таблица Inserted используется для создания отчета об изменении места проживания гражданина:

CREATE TRIGGER aiu_PERSON_trig ON Person

AFTER Insert, Update

AS

SET NoCount ON

IF Update(Adr)

SELECT Inserted.FIO + ' изменил место проживания на ' + Inserted.Adr

FROM Inserted;

Пример создания триггера, который при смене должности автоматически увеличивает зарплату:

CREATE TRIGGER Trig_test_1 ON Emp

AFTER UPDATE AS

BEGIN

IF (SELECT id_job FROM Inserted) <> (SELECT id_job FROM Deleted) BEGIN

UPDATE Emp SET Salary=Salary+100 WHERE id_emp= (SELECT id_emp FROM Inserted);

END;

END;

Триггер INSTEAD OF

Триггер INSTEAD OF создается оператором следующего вида:

CREATE TRIGGER имя_триггера ON имя_таблицы

INSTEAD OF операция AS

программный_код_триггера

Созданный триггер выполняется в ответ на событие, возникающее в начале операции, указанной за ключевым словом INSTEAD OF. Триггер INSTEAD OF заменяет транзакцию (т.е. выполняется вместо нее). Это подобно тому, как если бы триггер автоматически откатил операцию, для которой был создан.

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

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

-оператор пытается обновить необновляемое представление. В этом случае триггер INSTEAD OF обновляет таблицы, на которых построено данное представление;

-оператор пытается обновить величину, которая должна вычисляться;

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

В следующем примере создается и тестируется триггер замены операции вставки:

CREATE TRIGGER ioi_PERSON_trig ON Person INSTEAD OF Insert

AS

PRINT 'Триггер замены вставки' go

INSERT INTO Person (Nom, FIO, Rdate, Pol, SumD, Adr) VALUES(101,'Петров Петр Петрович','16.10.2002','М', 0, 'Зеленоград, 801-1');

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

Приведенный ниже триггер замены операции удаления активизируется при попытке удалить строку из главной таблицы PERSON и предварительно удаляет из подчиненной таблицы HAVE_D связанные строки, а затем строку из главной таблицы:

CREATE TRIGGER iod_PERSON_trig ON Person

INSTEAD OF Delete

AS

DECLARE @x int;

SELECT @x=Deleted.Nom from Deleted;

IF EXISTS (SELECT * from HAVE_D WHERE Nom = @x)

DELETE FROM HAVE_D WHERE Nom = @x;

DELETE FROM PERSON WHERE Nom = @x;

Из используемой в этом триггере виртуальной таблицы DELETED извлекается номер жителя, сведения о котором удаляются, и сохраняется в локальной переменной. Из-за отсутствия рекурсивности сам триггер активизируется только один раз оператором DELETE (например, DELETE FROM PERSON WHERE Nom=5), поэтому выполнение содержащегося в описании триггера оператора DELETE FROM PERSON WHERE Nom = @x происходит единожды.

Курсоры

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

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

Фактически, курсоры для SQL-запросов аналогичны итераторам для массивов. Основные действия с курсорами:

-создание или объявление курсора;

-открытие курсора (наполнение его данными, которые сохраняются в многоуровневой памяти);

-выборка из курсора и изменение с его помощью строк данных;

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

-освобождение курсора, т.е. удаление курсора как объекта, (закрытие необязательно освобождает ассоциированную с ним память).

Команды управления курсором:

DECLARE – создание или объявление курсора;

OPEN – открытие курсора, т.е. наполнение его данными;

FETCH – выборка из курсора и изменение строк данных с помощью курсора; CLOSE – закрытие курсора;

DEALLOCATE – освобождение курсора, т.е. удаление курсора как объекта.

Объявление курсора

Синтаксис:

DECLARE имя_курсора

[INSENSITIVE][SCROLL] CURSOR FOR SELECT_оператор

[FOR { READ_ONLY | UPDATE [OF имя_столбца[,...n]]}]

INSENSITIVE - статический курсор.

SCROLL - курсор можно.

SELECT-оператор задает тело запроса SELECT, с помощью которого определяется результирующий набор строк курсора.

FOR READ_ONLY - курсор только для чтения.

FOR UPDATE позволяет выполнять в курсоре изменение данных.

Объявление курсора в MS SQL

Синтаксис:

DECLARE имя_курсора CURSOR [LOCAL | GLOBAL]

[FORWARD_ONLY | SCROLL]

[STATIC | KEYSET | DYNAMIC | FAST_FORWARD] [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC] [TYPE_WARNING]

FOR SELECT_оператор

[FOR UPDATE [OF имя_столбца[,...n]]]

LOCAL - курсор виден только в пределах создавшего его пакета, триггера, хранимой процедуры или пользовательской функции.

GLOBAL - существует до закрытия текущего соединения. FORWARD_ONLY - последовательный курсор.

SCROLL - прокручиваемый курсор. STATIC - статический курсор. KEYSET - ключевой курсор. DYNAMIC - динамический курсор.

FAST_FORWARD - оптимизация для быстрого доступа к данным. Не может быть использован совместно с аргументами FORWARD_ONLY и OPTIMISTIC.

OPTIMISTIC - запрещается изменение и удаление строк.

Открытие курсора

Синтаксис:

OPEN {{[GLOBAL]имя_курсора } | @имя_переменной_курсора}

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

Выборка из курсора

Синтаксис:

FETCH [[NEXT | PRIOR | FIRST | LAST

| ABSOLUTE {номер_строки | @переменная_номера_строки}

| RELATIVE {номер_строки | @переменная_номера_строки}] FROM ]{{[GLOBAL ]имя_курсора }| @имя_переменной_курсора } [INTO @имя_переменной [,...n]]

FIRST - будет возвращена первая строка полного результирующего набора. LAST - возвращается последняя строка курсора.

NEXT - возвращается строка, находящаяся сразу после текущей. PRIOR - возвращает строку, находящуюся перед текущей.

ABSOLUTE возвращает строку по ее абсолютному порядковому номеру.

RELATIVE возвращает строку, находящуюся через указанное количество строк после текущей.

В конструкции INTO @имя_переменной [,...n] задается список переменных, в которых будут сохранены соответствующие значения столбцов возвращаемой строки. Порядок указания переменных должен соответствовать порядку столбцов в курсоре.

Изменение данных через курсор

UPDATE имя_таблицы SET {имя_столбца={ DEFAULT | NULL | выражение}}[,...n]

WHERE CURRENT OF {{[GLOBAL] имя_курсора} |@имя_переменной_курсора}

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

Удаление данных через курсор

DELETE имя_таблицы

WHERE CURRENT OF {{[GLOBAL] имя_курсора}

|@имя_переменной_курсора}

В результате будет удалена строка, установленная текущей в курсоре.

Закрытие курсора

Синтаксис:

CLOSE {имя_курсора | @имя_переменной_курсора}

После закрытия курсор становится недоступным для пользователей программы.

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

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

Освобождение курсора

Синтаксис:

DEALLOCATE { имя_курсора | @имя_переменной_курсора }

Пример использования курсора:

Использование курсора для вывода списка фирм и клиентов из Москвы:

DECLARE @firm Varchar(50), @fam Varchar(50), @message Varchar(80)

PRINT 'Список клиентов'

DECLARE klient_cursor CURSOR LOCAL FOR

SELECT Фирма, Фамилия FROM Клиент

WHERE Город='Москва'

ORDER BY Фирма, Фамилия

OPEN klient_cursor

FETCH NEXT FROM klient_cursor INTO @firm, @fam

WHILE @@FETCH_STATUS=0

BEGIN

SELECT @message='Клиент '+@fam+' Фирма '+ @firm

PRINT @message

FETCH NEXT FROM klient_cursor INTO @firm, @fam

END

CLOSE klient_cursor

DEALLOCATE klient_cursor

Транзакции

Под транзакцией понимается неделимая с точки зрения воздействия на БД последовательность операторов манипулирования данными (чтения, удаления, вставки, модификации), приводящая к одному из двух возможных результатов:

-либо последовательность выполняется, если все операторы правильные;

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

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

Управление транзакциями

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

Существуют три команды, которые используются для управления транзакциями:

-COMMIT – для сохранения изменений;

-ROLLBACK – для отмены изменений;

-SAVEPOINT – для установки особых точек возврата.

Управление транзакциями в среде MS SQL Server

SQL Server поддерживает три вида определения транзакций:

-явное;

-автоматическое;

-подразумеваемое.

По умолчанию SQL Server работает в режиме автоматического начала транзакций, когда каждая команда рассматривается как отдельная транзакция.

Если пользователю нужно создать транзакцию, включающую несколько команд, он должен явно указать транзакцию.

Для установки режима автоматического определения транзакций используется команда:

SET IMPLICIT_TRANSACTIONS OFF

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

SET IMPLICIT_TRANSACTIONS ON

Явные транзакции

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

- начало транзакции:

BEGIN TRAN[SACTION] [имя_транзакции | @имя_переменной_транзакции

[WITH MARK [‘описание_транзакции’]]]

- конец транзакции:

COMMIT [TRAN[SACTION] [имя_транзакции | @имя_переменной_транзакции]]

- создание внутри транзакции точки сохранения (СУБД сохраняет состояние БД в текущей точке и присваивает сохраненному состоянию имя точки сохранения):

SAVE TRAN[SACTION]

{имя_точки_сохранеия | @имя_переменной_точки_сохранения}

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

ROLLBACK [TRAN[SACTION]

[имя_транзакции | @имя_переменной_транзакции | имя_точки_сохранения

|@имя_переменной_точки_сохранения]]

Соседние файлы в папке лабы задания