Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование приложений баз данных с использованием СУБД MS SQL Server. Учебное пособие
.pdf
представления или таблицы, на которую ссылается процедура, а это
дает дополнительный механизм защиты данных.
Сервер SQL поддерживает следующие типы хранимых процедур:
системные хранимые процедуры – хранятся в базе данных
master. Система хранит процедуры (определяющиеся по префиксу sp_),
предоставляющие эффективные методы получения информации из
системных таблиц. Они позволяют системному администратору
выполнять администраторские задачи над
базой данных, которые
обновляют необходимые таблицы напрямую. Системные встроенные процедуры могут быть выполнены из любой базы данных;
пользовательские хранимые процедуры – создаются в опре-
деленных пользовательских базах данных;
расширенные встроенные процедуры (содержат в имени
префикс xp_) – разрабатываются в виде DLL (Dynamic Link Library,
динамически подгружаемая библиотека) и выполняются вне окружения SQL Server. Обычно такие процедуры
идентифицируются по
префиксу xp_.
Наибольший интерес для разработчика представляют, конечно, пользовательские хранимые процедуры. Для создания хранимой
процедуры необходимо воспользоваться следующей командой:
CREATE PROC[ EDURE ] [имя_схемы.]имя_процедуры
[ { @имя_параметра тип_параметра } ] [ ,...n ]
[ WITH
{ RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]
AS
<операторы Transact-SQL, составляющие тело процедуры>
Когда хранимая процедура создается, операторы проверяются
на синтаксическую корректность, чтобы в коде не было явных ошибок написания и использования операторов. На этом этапе логика
работы еще не может быть проверена. Если синтаксис ошибочен,
то возвращается ошибка и встроенная процедура не сохраняется.
Если синтаксис корректен, то сервер SQL сохраняет имя процедуры
системной таблице sysobjects, а текст в системной таблице
в
syscomments текущей базы данных.
40

Опция Recompile предписывает каждый раз генерировать план
запроса, а не помещать его в кэш. При указании опции Encryption
происходит шифрование кода процедуры в таблице syscomments.
Рассмотрим создание простой хранимой процедуры, которая
выводит список книг какого-либо издательства из таблицы book базы BookLibrary. В качестве входного параметра необходимо использовать имя издательства.
CREATE PROCEDURE GetIzd
@Izd nvarchar(50)
AS
select * from Book where Izd=@izd
Текст оператора Create необходимо
указать в окне запроса сре-
ды SQL Server Management Studio, после чего нажать кнопку Выполнить. Текущей базой данных во время выполнения запроса
должна быть база BookLibrary (рис. 10).
Рис. 10
Чтобы выполнить процедуру, необходимо в новом окне запроса выполнить оператор Exec и указать фактическое значение
параметра @Izd:
Exec GetIzd ’Прогресс’
Результаты выполнения процедуры представлены на рис. 11.
41

Рис. 11
Приведем более сложный пример. База данных BookLibrary
содержит информацию об экземплярах книг, хранящихся в библиотеке и выданных читателям. Если экземпляр выдается читателю, то
в таблице History появляется новая запись, в которой указаны идентификатор экземпляра книги, дата его выдачи и номер читательского билета. Поле даты возврата остается пустым. Следовательно,
чтобы
зафиксировать возвращение книги в библиотеку, необходимо заполнить это поле датой реального возврата книги читателем.
Текст процедуры приведен ниже:
CREATE proc SetBookBack
@id int,@dt1 datetime,@N int
AS
BEGIN
if exists(select * from History where IdItem=@id and NB=@N and
Dat1 is null)
begin
42

update History set Dat1=@dt1 where IdItem=@id and NB=@N and
Dat1 is null
print 'Экэемпляр книги возвращен'
end
else
print 'Запись не найдена'
print 'Выполнение закончено'
END
Здесь при выполнении надо указать три входных параметра:
уникальный идентификатор экземпляра возвращаемой книги, дату
возврата и номер билета читателя, взявшего книгу. Процедура проверяет наличие записи с данными параметрами и пустым значением
даты возврата. Если запись присутствует, в
ней проставляется дата
возврата книги, в противном случае выдается сообщение об отсутствии нужной записи. Таблица History до выполнения процедуры
имела вид
1000002 2013-02-12 00:00:00.000 2013-03-12 00:00:00.000 100001
1000014 2014-07-12 00:00:00.000 NULL 100002
NULL NULL NULL NULL
Из таблицы следует, что читатель с билетом 100002 держит на
руках экземпляр книги, имеющий идентификатор 1000014.
Чтобы зафиксировать возврат книги с датой возврата
12.08.2014, необходимо выполнить хранимую процедуру SetBook-
Back. Вызов процедуры в Server SQL Studio и его результаты пока-
заны на рис. 12.
5.2. Пользовательские функции
Пользовательские функции сходны с хранимыми процедурами. Однако, в отличие от хранимых процедур, они могут использоваться только в запросах так же, как и системные функции. Как
и хранимые процедуры, они могут иметь один или несколько параметров, но возвращают скалярные типы данных, например int,
decimal, varchar, или тип данных table, т. е. таблицу.
43

Рис. 12
Всего сервер SQL поддерживает три типа функций, опреде-
ленных пользователем:
скалярные функции – похожи на встроенные функции;
функция, возвращающая таблицу (inline) – возвращает ре-
зультат единичного оператора SELECT. Он похож на объект просмотра, но имеет большую эластичность благодаря использованию
параметров и расширяет возможности индексированного объекта
просмотра;
многооператорная функция (multiline) – возвращает табли-
созданную одним или несколькими операторами Transact-SQL,
цу,
чем напоминает хранимые процедуры. В отличие от процедур, на
такие функции можно ссылаться в операторе SELECT как на объект просмотра.
Функции не могут выполнять следующие действия:
изменять состояние сервера или базы данных;
модифицировать данные в таблице;
вызывать функцию с внешним эффектом, такую как
RAND;
создавать временные таблицы и обращаться к ним.
Операторы, создающие пользовательские функции, сходны
с аналогичными для хранимых процедур. Главные различия – тре-
44

бование указать значение RETURNS с типом возвращаемого значения и заканчивать функцию выражением RETURN.
Определение скалярной функции следующее:
CREATE FUNCTION[имя_схемы.]имя_функции
[ { @имя_параметратип_параметра } ] [ ,...n ]
RETURNS<тип возвращаемого скалярного значения>
[ WITH<список опций>]
AS
BEGIN
<операторы Transact-SQL, составляющие тело процедуры>
RETURN<скалярное значение>
END
В качестве примера построим скалярную функцию, выводящую количество экземпляров книг
, находящихся на руках у кон-
кретного читателя.
Входным параметром будет номер читательского билета. Чтобы найти нужное значение, необходимо сосчитать количество записей, соответствующих данному читателю, с пустым значением
даты возврата книги Dat1.
Функция создается следующим оператором Transact-SQL:
CREATE FUNCTION dbo.GetQty (@NB int)
RETURNS int
AS
BEGIN
DECLARE @N int
SELECT @N= COUNT(*) FROM History WHERE NB=@NB
AND Dat1 IS NULL
RETURN @N
END
Чтобы проверить, правильно ли работает функция, создадим
и выполним в новом окне среды
Server Management Studio следующий запрос, выдающий количество книг, взятых читателем с номером билета 100001:
Результаты выполнения запроса и исходная таблица History
представлены на рис. 13.
45

Рис. 13
Пользовательская функция, возвращающая тип данных table,
может объявить внутреннюю табличную переменную и вернуть содержимое этой переменной. Такие функции называют rowsetфункциями. Они могут использоваться в запросах вместо таблиц
и представлений там, где Transact-SQL это допускает.
Пользовательские функции, возвращающие таблицы, могут
стать достойной альтернативой представлениям. Представление
(view) ограничено одним выражением select, а пользовательские
функции способны
включать дополнительные выражения, что по-
зволяет создавать более сложные и мощные конструкции.
Построим теперь inline-функцию, возвращающую таблицу как
результат выполнения единичного оператора SELECT.
Рассмотрим функцию, которая выдает таблицу, содержащую
ISBN, наименование места издания и имя издательства всех книг,
выпущенных в определенном году, т. е. в качестве входного параметра используется год издания
.
Текст оператора SQL-Transact, создающего эту функцию, приведен ниже:
CREATE FUNCTION GetBookOfGod(@god int)
RETURNS TABLE
AS
RETURN SELECT Isbn,Name,mesto,Izd from Book where God=@god
После выполнения оператора create в базе данных BookLibrary
появится функция GetBookOfGod. Создадим запрос, использующий
46

эту функцию. Его результатом будут данные о книгах, изданных
в Москве (поле mesto должно быть равно ‘М.’), взятые из таблицы,
содержащей информацию о книгах, выпущенных в 1998 году. Последняя должна быть получена с помощью только что созданной
функции GetBookOfGod. Запрос и его результаты представлены
на рис. 14.
Рис. 14
5.3. Триггеры
Триггер – это особо хранимая процедура, которая запускается
автоматически при вставке, удалении или изменении строк таблицы. Каждый триггер связан с конкретной таблицей. Когда пользователь начинает изменение данных в таблице, сервер автоматически инициирует выполнение транзакции, в которой выполняется
триггер. Триггер либо фиксирует, либо выполняет эту транзакцию.
При фиксации транзакции производится
фиксирование и изменений, сделанных пользователем, и изменений, сделанных триггером.
Триггеры бывают трех типов, каждый из которых квалифицируется
по названию команд, на который они реагируют:
47

INSERT TRIGGER. Триггеры этого типа вызываются при
попытке пользователя добавить данные в таблицу командой
INSERT;
UPDATE TRIGGER. Этот тип триггеров выполняется при
попытке изменения данных в таблице командой UPDATE;
DELETE TRIGGER. Этот тип триггеров выполняется при
попытке удаления данных с помощью команды DELETE.
Для отслеживания изменений, производимых пользователем,
сервер автоматически создает две виртуальные таблицы – deleted
inserted.
и
При вызове триггера INSERT таблица inserted содержит стро-
ки, вставляемые пользователем. В таблице deleted ничего нет.
При вызове триггера DELETE таблица deleted содержит стро-
ки, которые будут удалены. Таблица inserted ничего не содержит.
При вызове триггера UPDATE в таблице deleted находятся
строки, которые собирается изменить пользователь, а в таблице
inserted – строки, которые будут внесены в таблицу вместо соответствующих
строк таблицы deleted.
Эти таблицы не существуют физически, а представляют логические структуры, изменять которые нельзя.
Для создания триггера используется команда CREATE
TRIGGER, имеющая синтаксис:
CREATE TRIGGER <имя_триггера> ON <имя_таблицы> AFTER
{INSERT | DELETE | UPDATE}
AS
<операторы TRANSACT-SQL>
Ниже приведены примеры триггеров разных типов, созданных
для таблицы book базы данных BookLibrary.
Пример 1. Необходимо создать триггер, который запрещает
вставку записи новой
книги издательства «Наука» в таблицу book,
если количество экземпляров книги (столбец kol) меньше 6.
CREATE TRIGGER trigger1
ON dbo.book
after INSERT
AS
if exists(select * from inserted where izd='Наука' and kol<6)
begin
48

raiserror('Not inserted,izd=Наука,kol<6',1,11)
rollbacktran
end
Пример 2. Требуется создать триггер, который запрещал бы
удаление книг издательства «Прогресс».
create trigger trigger2
ondbo.book
after delete
as
if exists(select * from deleted where izd='Прогресс ')
begin
raiserror('Not delete, izd=Прогресс ',1,11)
rollbacktran
end
Пример 3. Необходимо создать триггер, который запрещал бы
изменение столбца ISBN, а также запрещал бы изменять наименование книг издательства «Наука».
CREATE TRIGGER trigger3
ON dbo.book
after update
AS
if update(ISBN)
begin
raiserror('Column ISBN is not updated',1,11)
rollbacktran
return
end
if update(Name) and exists(select * from deleted where izd='Наука')
begin
raiserror('You cannot change the name of the books publisher
Наука',1,11)
rollback tran
end
В заключение следует отметить
, что хотя триггеры и могут
использоваться для выполнения самых разнообразных задач, но необходимость выполнения триггера при каждом изменении таблицы
существенно замедляет работу системы.
49
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
