
3. Хранимые процедуры
Хранимые процедуры - это программы SQL, скомпилированные при первом выполнении и затем сохраненные для дальнейшего применения. Они обладают определенными преимуществами перед программами, выполняемыми немедленно и не предполагающими последующего применения:
Процедуры, которые были скомпилированы ранее, выполняются более быстро.
Они могут получать и возвращать параметры - переменные, используемые для передачи данных хранимым процедурам и от них - что позволяет создавать модули-утилиты или иным способом разбивать на модули большие и сложные программы.
Рассмотрим пример.
Параметр. Переменная, используемая для передачи данных хранимой процедуре и получения данных от нее.
Предположим, что нам часто приходится считать число работников в таблице worker. После того, как мы определим локальную переменную @wo_count (число работников), мы можем написать запрос:
select @wo_count = count (*) from worker
Или вместо этого мы можем создать процедуру:
create procedure count_workers @wo_count int output
as
select @wo_count = count (*) from worker
Первая строка этого выражения
create procedure count_workers @wo_count int output
присваивает процедуре имя, «count_workers» и сразу после этого определяет все параметры, задавая их типы данных и указывая, чем они являются - входными или выходными параметрами. В нашем примере
@wo_count - выходной параметр типа int (целое число). Теперь посмотрим, как эта процедура будет работать.
Когда процедура вызывается, то выполняется содержащийся в ней запрос
select @wo_count = count (*) from worker,
Результат помещается в выходную переменную @wo_count и возвращается вызывающей программе. Выходные параметры задаются словом «output» или «out» после типа данных. Входными параметрами будут все параметры, не помеченные как выходные. Ключевое слово «as» сигнализирует об окончании определений параметров и начале определения процедуры. Все, что стоит после «as», составляет выполняющуюся часть процедуры.
Теперь рассмотрим, как выполняется процедура count_workers. Во-первых, мы определяем локальную переменную @worker_count. Затем мы выполняем процедуру:
declare @worker_count int
execute count_workers @worker_count output
Команда execute вызовет выполнение ранее определенной процедуры count_workers; результат выполнения будет помещен в локальную переменную @worker_count.
Вы можете видеть, что таким подходом пользоваться проще, чем каждый раз писать запрос
select @wo_count = count (*) from worker
Разумеется, преимуществ применения хранимых процедур существенно больше, когда сама процедура обширнее и сложнее.
Во втором, более сложном примере, предположим, что мы хотели бы сохранить процедуру, подсчитывающую среднюю ставку рабочих указанной специальности. Это означает, что вызывающая процедуру программа передает ей тип специальности, а процедура возвращает величину средней ставки работников этой специальности. Мы создадим процедуру calc_wage_fcns следующим образом:
create procedure calc_wage_fcns @avg_hrly_rate money output,
@skill_type char (10)
as
select @avg_hrly_rate = avg (hrly_rate)
from worker
where skill_type = @skill_type
У этой хранимой процедуры есть выходной параметр @avg_hrly_rate (средняя почасовая ставка) и входной - @skill_type. Вызывающая программа должна задавать локальную переменную типа money (денежные суммы) для фиксации выходного параметра, и значение типа специальности. Более того, в ней эти параметры должны быть указаны в том же порядке, в котором они перечислены при определений процедуры. Приведем пример вызова процедуры calc_wage_fcns, в котором все это сделано:
declare @avg_wage money
exec calc wage_fcns @avg_wage output, Штукатур
Обратите внимание, что команду «execute» можно сократить до «ехес». Хотя значение входного параметра (в нашем случае «Штукатур») является символьной величиной, его не нужно заключать в кавычки, за исключением тех случаев, когда оно дополнено пробелами, содержит знаки препинания или начинается с цифры. Процедура calc_wage_fcns подставит значение «Штукатур» в переменную @skill_type, и результат ее выполнения будет аналогичен результату выполнения запроса
select @avg_hrly_rate = avg (hrly_rate)
from worker
where skill_type = 'Штукатур'.
Будет подсчитана средняя почасовая ставка штукатура, и когда значение будет возвращено вызывающей программе, оно будет помещено в переменную @avg_wage.
Значения по умолчанию. При определении хранимой процедуры можно задать значение параметра по умолчанию. Если вызывающая программа не задает значения входного параметра, то программа использует значение по умолчанию. Значением по умолчанию может быть любое допустимое значение заданного типа данных, включая
пустое. Рассмотрим пример, в котором используется пустое значение. Мы просто видоизменим предыдущий пример. В случае, если вызывающая программа задает только выходной параметр, но не указывает тип специальности, мы будем считать среднюю ставку всех работников. Измененная процедура выглядит следующим образом:
Значение параметра по умолчанию. Значение параметра, задаваемое системой в том случае, если вызывающая программа опускает его значение.
create procedure calc_wage_fcns @avg_hrly_rate money output,
@skill_type char (10) = null
as
if @skill_type is null
select @avg_hrly_rate = avg (hrly_rate)
from worker
else
select @avg_hrly_rate = avg (hrly_rate}
from worker
where skill_type = @skill_type
Если вы сравните эту версию с предыдущей версией, то увидите, что значение по умолчанию определяется сразу после задания типа данных параметра:
@skill_type char (10) = null.
Помещая «null» после определения параметра, мы говорим, что если никакое значение параметру не передано, то параметр считается имеющим пустое значение. Выполняемая часть процедуры изменена, так, чтобы учитывать такую возможность - тип специальности не передан вызывающей программой.
Применение команды RETURN. Когда последняя команда процедуры выполнена, процедура завершается и возвращает управление вызывающей процедуре. Как быть, если логика процедуры такова, что мы хотим выйти из нее раньше? Команда RETURN обрывает выполнение хранимой процедуры и немедленно возвращает управление вызывающей программе. Предположим, что мы хотим придать одной хранимой процедуре несколько разных функций. Например, мы хотим позволить пользователю запрашивать максимальную, минимальную или среднюю почасовую ставку из таблицы worker. Процедура, которая это делает, выглядит так:
create procedure calc_wage_fcns @fcn_type char (3),
@ret_value money output
as
if @fcn_type = 'max'
begin
select @ret_vaiue = max (hrly_rate) from worker
return
end
if @fcn_type = 'min’
begin
select @ret_value = min (hriy_rate) from worker
return
end
if @fcn_type = 'avg'
begin
select @ret_value = avg (hrly_rate) from worker
return
end
В этом примере вызывающей программе требуется одна из трех функций. Если выбрана функция «max», то мы вычисляем значение и немедленно возвращаемся в исходную программу, так как не хотим вычислять остальные две функции. Из этого примера нетрудно понять, как команда RETURN может применяться в хранимых процедурах.
Далее рассмотрим технологию работы с хранимыми процедурами в SQL-сервере.
Воспользуемся возможностями утилиты SQL Server Enterprise Manager.
Все хранимые процедуры в базе данных находятся в специально отведенном списке Stored Procedures, который видим при открытии базы данных. Следует обратить внимание на перечень системных процедур, используемых при работе SQL-сервера, список которых также находится в этой группе.
При этом в колонке Type возле имени процедур находится ключевое слово System, которое показывает принадлежность данной процедуры к группе системных процедур. С другой стороны, все процедуры, создаваемые пользователем, помечаются ключевым словом User в колонке Type.
Для создания новой процедуры выберите команду New Stored Procedures меню Action, после чего на экране отобрази диалоговое окно, в котором будет расположена область для ввода текста процедуры (рис. 3).
Введем текст вышерассмотренной процедуры:
create procedure count_workers @wo_count int output
as
select @wo_count = count (*) from worker.
Следующим этапом будет проверка работоспособности созданной процедуры. Для этого запустите утилиту SQL Server Query Analyzer, после чего осуществите подключение к требуемому серверу баз данных. Выберите базу данных Premier в выпадающем списке DB, после чего введите следующую SQL-команду:
ЕХЕС count_workers
С помощью SQL-команды ЕХЕС осуществляется запуск хранимых процедур, причем весь, процесс их выполнения происходит на самом компьютере - сервере. Использование хранимых процедур существенно отражается на производительности компьютеров рабочих станций. Другими словами, данная технология позволяет использовать компьютеры рабочих станций на уровне клавиатурного ввода, а все основные задачи при этом перекладываются на компьютер-сервер.
ЗАДАНИЕ.
1. Создайте команды языка управления потоками для каждого из следующих случаев:
а. Если средний status (статус) здания больше 1, то увеличить почасовую ставку плотников на 1 доллар в час.
b. Если менеджер 1311 имеет более 30 дней работы на разных зданиях, уменьшить число дней его работы на каждом здании на 1 день и повторять эту операцию до тех пор, пока суммарное число дней его работы не станет меньше 25 дней.
2. Создайте хранимую процедуру, получающую в качестве параметра skill_type, вычисляющую и возвращающую среднее число дней среди кортежей назначений работников этой специальности.