[WHERE..]
[GROUP BY. . ]
[ORDER BY. . ]
INTO <список-переменных> DO
BEGIN
< блок-обработки>
. . .
[SUSPEND] ;
END
В качестве примера рассмотрим следующую процедуру, получающую набор от оператора SELECT, который передает строки, по одной за один раз, в буфер курсора процедуры. Она проходит по набору, устанавливая значения для набора переменных в соответствии со спецификацией таблицы. В конце цикла процедура добавляет запись во внешнюю таблицу.
CREATE PROCEDURE PROJECT_MEMBERS
AS
DECLARE VARIABLE PROJ_NAME CHAR(23);
DECLARE VARIABLE EMP_NO CHAR(6);
DECLARE VARIABLE LAST_NAME CHAR(23);
DECLARE VARIABLE FIRST_NAME CHAR (18);
DECLARE VARIABLE HIRE_DATE CHAR(12);
DECLARE VARIABLE JOB_TITLE CHAR(27) ;
DECLARE VARIABLE CRLF CHAR (2);
BEGIN
CRLF = ASCII_CHAR(13) || ASCII_CHAR(10);
/* Windows EOL - признак конца строки */
FOR SELECT DISTINCT
P.PROJ_NAME,
E.EMP_NO,
E.LAST_NAME,
E.FIRST_NAME,
E.HIRE_DATE,
J.JOB_TITLE
FROM EMPLOYEE E
JOIN JOB J ON E.JOB_CODE = J.JOB_CODE
JOIN EMPLOYEE_PROJECT EP ON E.EMP_NO = EP.EMP_NO
JOIN PROJECT P ON P.PROJ_ID = EP.PROJ_ID
ORDER BY P.PROJ_NAME, E.LAST_NAME, E.FIRST_NAME
INTO /* переменные для столбцов */
:PROJ_NAME, :EMP_NO, :LAST_NAME, :FIRST_NAME,
:HIRE_DATE, :JOB_TITLE
DO
BEGIN /* начинает цикл присваивания значений переменным */
PROJ_NAME = ""И CAST (PROJ_NAME AS CHAR(20) ) || "" ||' , ' ;
EMP_NO = CAST (EMP_NO AS CHAR (5) ) || ' , ' ;
LAST_NAME = ""|| CAST (LAST_NAME AS CHAR(20) ) || "" ||' , ' ;
FIRST_NAME = ""|| CAST (FIRST_NAME AS CHAR (15) ) || "" || ' , ';
HIRE_DATE = CAST(HIRE_DATE AS CHAR(11)) || ' , ';
JOB_TITLE = ""|| CAST (JOB_TITLE AS CHAR (25) ) || "" ;
INSERT INTO EXT_FILE
VALUES (:PROJ_NAME, :EMP_NO, :LAST_NAME,
:FIRST_NAME,:HIRE_DATE, :JOB_TITLE,
CRLF) ;
END /* завершает цикл DO */
END ^
! ! !
ВНИМАНИЕ! Если выходному параметру не присваивается значение, его значение будет непредсказуемым, что может привести к ошибкам. Процедура должна обеспечить инициализацию всех выходных параметров до начала процесса присваивания значений; это должно гарантировать, что оператор SUSPEND передаст допустимые выходные данные.
. ! .
Оператор SUSPEND имеет специфическое использование в конструкции FOR ... SELECT ... INTO ... DO. Если SUSPEND включен в цикл DO, то после того, как SELECT прочтет строку в переменные строки, цикл будет ждать, когда эта строка будет выведена в кэш строк сервера перед получением следующей строки из курсора SELECT. Такая операция позволяет создавать в Firebird хранимые процедуры выбора.
В следующей главе мы более подробно рассмотрим использование операторов SELECT, которые возвращают множество строк в хранимые процедуры, и технику написания хранимых процедур выбора.
Оператор SUSPEND недопустим в триггерах. В выполняемых хранимых процедурах он имеет тот же эффект, что и оператор EXIT - т. е. он немедленно завершает процедуру, а все операторы, следующие за ним, никогда не будут выполняться.
По контрасту, если процедура выбора имеет выполняемые операторы, следующие за последним оператором SUSPEND В процедуре, то все эти операторы будут выполнены, даже если нет больше строк, возвращаемых вызвавшей программе. Процедуры такого рода завершаются финальным оператором END.
Операторы управления потоком
PSQL содержит множество операторов, которые влияют на поток управления в кодах модулей. Только что рассмотренный оператор SUSPEND передает управление назад вызвавшей процедуре или клиентской программе, ожидая, когда только что обработанная строка будет получена из кэша строк сервера.
В процедурах выбора и в выполняемых процедурах EXIT вызывает переход на финальный оператор END В процедуре. Он не имеет смысла в триггерах.
Поведение операторов SUSPEND, EXIT и END описано в табл. 29.2.
Таблица 29.2. Операторы SUSPEND, EXIT и END
Тип модуля | SUSPEND | EXIT | END |
Процедура выбора | Выполнение приостанавливается, пока вызвавшее приложение или процедура получает следующий набор выходных переменных | Возвращает значения (если присутствуют) и переходит на финальный END | Возвращает управление приложению и устанавливает SQLCODE В 100 |
Выполняемая процедура | Переходит на финальный END - не рекомендуется | Переходит на финальный END | Возвращает значения и передает управление приложению |
Триггеры | Никогда не используется | Переходит на финальный END | Передает управление следующему триггеру той же фазы (BEFORE или AFTER), что и у текущего, если тот существует. Иначе завершает работу триггеров этой фазы |