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

Программирование приложений баз данных с использованием СУБД MS SQL Server. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
представления или таблицы, на которую ссылается процедура, а это дает дополнительный механизм защиты данных.
Сервер 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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]