
- •Виды хранимых процедур в Firebird
- •Пример выполнения практической работы
- •Некоторые дополнительные сведения Использование переменных
- •Управляющие конструкции begin..End
- •Стандартные операторы
- •И еще примеры Процедуры без параметров
- •Процедуры с входными параметрами
- •Использование входных параметров и локальных переменных
- •Процедуры с выходными параметрами
- •Процедуры с входными и выходными параметрами
- •Обработка данных в процедурах
- •Селективные процедуры
- •Вызов процедур из процедур или триггеров
- •Рекурсивные процедуры
- •Особенность вложенных вызовов процедур и рекурсивных процедур
- •Планы процедур и производительность Планы процедур
- •Производительность
- •Контрольные вопросы
Стандартные операторы
Стандартными операторами являются SELECT, INSERT, UPDATE и DELETE.
В СУБД Firebird оператор SELECT не позволяет использовать ключевое слово INTO для создания новой таблицы «на лету». Вместо этого, ключевое слово INTO используется для связи результата запроса с переменной.
SELECT state INTO :state /* --> обратите внимание на
":" перед именем переменной */
FROM authors
WHERE auth_name = 'John'
И еще примеры Процедуры без параметров
Такие процедуры могут выполнять какие-либо действия, которым не требуется входные данные для работы, и которым не требуется выдавать какой-либо результат
create procedure test
as
begin
insert into testtable (field1) values (1);
end
Каждый оператор в процедуре должен быть завершен символом ;
В такой процедуре могут быть объявлены локальные переменные (declare variable), для организации каких-либо вычислений.
Например
create procedure test
as
declare variable i int;
begin
i=1;
insert into testtable (field1) values (:i);
end
Такие процедуры вызываются оператором
EXECUTE PROCEDURE <имя процедуры>
Процедуры с входными параметрами
Пример
create procedure test (i int)
as
begin
insert into testtable (field1) values (:i);
end
вызывается следующим образом:
EXECUTE PROCEDURE <имя_процедуры> (список_параметров_через_запятую)
обрамление списка параметров круглыми скобками необязательно, но желательно.
Использование входных параметров и локальных переменных
Входные параметры и локальные переменные в процедурах обычно указывают предваряя их имя двоеточием.
Например
select field1 from table
where field2 > :param1
into :param2;
Двоеточие не указывается только в том случае, когда переменной присваивают какое-либо значение через =
i=:i+1;
указание двоеточия не является обязательным, однако настоятельно рекомендуется для облегчения "видимости" переменных в коде процедуры, и отличия переменных от имен полей таблиц.
Процедуры с выходными параметрами
create procedure test
returns (s varchar(30))
as
begin
s='aaa'||'bbb';
end
Вы можете создать эту процедуру в базе employee, и при выполнении процедура выдаст результат выполнения запроса - строку 'aaabbb'. Команда
s='aaa'||'bbb';
служит просто для примера, что в процедуре можно оперировать совершенно любыми данными, вычислениями и т.п.
Если необходимо выполнить такую процедуру в другой процедуре или триггере, то это можно сделать
EXECUTE PROCEDURE <имя_процедуры> RETURNING_VALUES <список_переменных>
Например
create procedure test2
as
declare variable s2 varchar(30);
beigin
execute procedure test returning_values :s2;
end
В переменной s2 мы получим значение, возвращенное из процедуры test.
Процедуры с входными и выходными параметрами
Комбинация из двух предыдущих разделов, к которой вряд-ли можно что-то добавить.
Обработка данных в процедурах
В процедурах можно выполнять практически любые действия - обновление, удаление, выборку и т.д. Чаще всего используется выборка данных и их последующая обработка. Если вы хотите выполнить запрос, который однозначно вернет только одну запись, то можно в коде процедуры написать следующее:
select currency
from country
where country = 'England'
into :s;
После выполнения запроса в переменной s окажется значение выбранного столбца currency. Если запрос не вернул ни одной записи, то в переменной s окажется то значение, которое было раньше!
s='none';
select currency
from country
where country = 'Russia'
into :s;
Поскольку записи о валюте России в таблице country базы employee по умолчанию нет, то в переменной s останется строка 'none'. Помните об этом. Если такая ситуация может возникнуть, обязательно инициализируйте переменные или значением null, или другим значением, по которому вы можете определить, что запрос не вернул ничего - например такое значение, которого в этом столбце в этой таблице не может быть никогда.
примечание: в Firebird 2.0 и выше переменная ROW_COUNT позволяет после выполнения оператора DML определить, сколько записей он обработал (в версии 1.5 row_count для select всегда возвращал 0) . Если select из предыдущего примера не вернул ни одной записи, то ROW_COUNT будет равно 0. Таким образом, обработку "пустых" запросов можно упростить следующим образом:
select currency from country where country = 'USA' into :s;
if (ROW_COUNT = 0) then -- запрос не вернул ни одной записи
...
Разумеется, ROW_COUNT можно использовать и для запросов UPDATE, DELETE (для INSERT нет смысла, т.к. он или вставит 1 запись, или вернет ошибку).
Если же запрос вернет 2 или более записи, то вы получите сообщение
multiple rows in singleton select
что как раз и означает, что сервер ожидал одно значение, а запросом было возвращено множество. Поскольку сервер не знает, как ему втиснуть это множество значений в одну переменную, возвращается ошибка.
Для обработки запросов, возвращающих множество записей, нужно использовать конструкцию FOR SELECT
create procedure calcsalarysum
returns (sm numeric(15,2))
as
declare variable s numeric(15,2);
begin
sm=0;
for select salary
from employee
into :s
do
sm=:sm+:s;
end;
Процедура делает следующее - перебирает всю таблицу employee, выбирает значение столбца salary для каждого сотрудника, и накапливает эти значения в виде суммы в возвращаемую переменную sm. В итоге, в переменной будет сумма зарплат всех сотрудников. Разумеется, для подобных вычислений создавать процедуру не требовалось, достаточно было выполнить простой запрос
select sum(salary) from employee
Однако, этот пример показывает возможность обработки данных каждой записи, возвращаемой запросом. Блок do может быть сколь угодно сложным, и состоять из нескольких операторов в блоке begin end
for select ...
do
begin
...
...
end
где может быть еще один вызов for select, и т.п.