Шрифт:
Интервал:
Закладка:
Контекстные переменные могут применяться везде, где могут быть использованы обычные переменные. Значение NEW для столбца строки может быть изменено только до соответствующего действия. Значения OLD являются значениями только для чтения. Подробности и примеры использования см. в главе 31.
! ! !
СОВЕТ. Поскольку Firebird создает триггеры для реализации ограничений CHECK, контекстные переменные OLD и NEW могут использоваться непосредственно в ограничениях CHECK, например:
ALTER TABLE EMPLOYEE
ADD CONSTRAINT EMPLOYEE_SALARY_RAISE_CK
CHECK ((OLD.SALARY IS NULL) OR (NEW.SALARY > OLD.SALARY));
. ! .
Операторы SELECT ... INTO
Используйте оператор SELECT С предложением INTO для поиска значений столбцов в таблицах и сохранения их в локальных переменных или выходных аргументах.
Одиночный оператор SELECTОбычный оператор SELECT В PSQL должен возвращать не более одной строки из базы данных- стандартный одиночный (singleton) оператор SELECT. ЕСЛИ оператор возвращает более одной строки, то будет выдано исключение. Предложение ORDER BY недопустимо в одиночном SELECT кроме случая, когда используется оператор SELECT FIRST 1. (Информацию об использовании квалификатора FIRST см. В znaee 21.)
Обычные правила применяются к входному списку, предложению WHERE и предложению GROUP BY, если оно используется. Предложение INTO требуется и должно быть последним предложением в операторе.
Пример одиночного оператора SELECT В параметризованном запросе DSQL в приложении:
SELECT SUM(BUDGET), AVG(BUDGET)
FROM DEPARTMENT
WHERE HEAD_DEPT = :head_dept;
Для использования этого оператора в процедуре объявите локальные переменные или выходные аргументы и добавьте предложение INTO в конец:
. . .
DECLARE VARIABLE TOT_BUDGET NUMERIC(18,2);
DECLARE VARIABLE AVG_BUDGET NUMERIC(18,2);
. . .
SELECT SUM(BUDGET), AVG(BUDGET)
FROM DEPARTMENT
WHERE HEAD_DEPT = :head_dept
INTO :tot_budget, :avg_budget;
Операторы SELECT для множества строкЛюбой модуль PSQL может оперировать с множеством входных строк, полученных из оператора SELECT, когда он содержит структуру цикла, который может "перемещаться" по набору и выполнять одинаковую обработку каждой строки. PSQL не может обрабатывать многострочные наборы другим способом, и при отсутствии контекста цикла многострочная выборка данных вызовет исключение ("Multiple rows in singleton select" - "Множество строк в одиночном операторе SELECT").
Циклы FOR SELECT...Основным методом реализации структуры цикла для обработки многострочных входных наборов является структура FOR ... SELECT ... INTO ... DO. Его упрощенный синтаксис:
FOR SELECT <список-спецификации-набора>
FROM имя-таблицы
[JOIN..]
[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Оператор SUSPEND имеет специфическое использование в конструкции FOR ... SELECT ... INTO ... DO. Если SUSPEND включен в цикл DO, то после того, как SELECT прочтет строку в переменные строки, цикл будет ждать, когда эта строка будет выведена в кэш строк сервера перед получением следующей строки из курсора SELECT. Такая операция позволяет создавать в Firebird хранимые процедуры выбора.
В следующей главе мы более подробно рассмотрим использование операторов SELECT, которые возвращают множество строк в хранимые процедуры, и технику написания хранимых процедур выбора.
Оператор SUSPEND недопустим в триггерах. В выполняемых хранимых процедурах он имеет тот же эффект, что и оператор EXIT - т. е. он немедленно завершает процедуру, а все операторы, следующие за ним, никогда не будут выполняться.
По контрасту, если процедура выбора имеет выполняемые операторы, следующие за последним оператором SUSPEND В процедуре, то все эти операторы будут выполнены, даже если нет больше строк, возвращаемых вызвавшей программе. Процедуры такого рода завершаются финальным оператором END.
Операторы управления потоком
PSQL содержит множество операторов, которые влияют на поток управления в кодах модулей. Только что рассмотренный оператор SUSPEND передает управление назад вызвавшей процедуре или клиентской программе, ожидая, когда только что обработанная строка будет получена из кэша строк сервера.
EXITВ процедурах выбора и в выполняемых процедурах EXIT вызывает переход на финальный оператор END В процедуре. Он не имеет смысла в триггерах.
Поведение операторов SUSPEND, EXIT и END описано в табл. 29.2.
Таблица 29.2. Операторы SUSPEND, EXIT и END
Тип модуля
SUSPEND
EXIT
END
Процедура выбора
Выполнение приостанавливается, пока вызвавшее приложение или процедура получает следующий набор выходных переменных
Возвращает значения (если присутствуют) и переходит на финальный END
Возвращает управление приложению и устанавливает SQLCODE В 100
Выполняемая процедура
Переходит на финальный END - не рекомендуется
Переходит на финальный END
Возвращает значения и передает управление приложению
Триггеры
Никогда не используется
Переходит на финальный END
Передает управление следующему триггеру той же фазы (BEFORE или AFTER), что и у текущего, если тот существует. Иначе завершает работу триггеров этой фазы
LEAVEВ Firebird 1.5 появился оператор LEAVE для выхода из блоков. Он заменил оператор BREAK, который был частично реализован в версии 1.0.x. Вот пример его использования в цикле WHILE нашей процедуры IS_PORK_SAFE:
WHILE (SI < 9) DO
BEGIN
SI = SI + 1; /* арифметическое выражение */
IF (SUBSTRING(SMONTH FROM 1 FOR 1) = 'R') THEN
BEGIN
RESPONSE = 'YES'; /* простая константа */
LEAVE;
END
SMONTH = SUBSTRING(SMONTH FROM 2);
/* функциональное выражение */
END
LEAVE приводит к выходу из цикла - в нашем случае останавливается проверка букв слова на символ "R". Если ветвь, содержащая оператор LEAVE, не выполняется, то выполнение продолжается до конца цикла.
EXCEPTIONОператор EXCEPTION останавливает выполнение и передает управление первому блоку обработки исключений (блоку, начинающемуся с ключевого слова WHEN), который может обработать исключение. Если для этого исключения не найден обработчик, управление передается финальному оператору END и процедура завершается аварийно. Когда происходит такое, один или более кодов исключения передается назад клиенту через вектор состояния ошибок (массив).
Оператор EXCEPTION используется в блоке IF ... THEN ... ELSE для вызова пользовательских исключений, предварительно определенных как объекты базы данных. Сервер Firebird вызывает свои собственные исключения для SQL и контекста ошибок. Поток управления в этих случаях точно такой же, как и при вызове пользовательских исключений.
Синтаксис и техники вызова и обработки исключений описаны в главе 32.
EXECUTE STATEMENT
Firebird 1.5 вводит расширение PSQL, поддерживающее выполняемые строки. Приложение или процедура могут передать оператор DSQL (DDL или DML) в виде строки входного аргумента (либо процедура может сконструировать эту строку как локальную переменную) для выполнения с использованием EXECUTE STATEMENT.
EXECUTE STATEMENT добавляет гибкости хранимым процедурам и триггерам, но с высоким риском ошибок. Возвращаемые значения жестко проверяются на типы данных, чтобы избежать непредсказуемых исключений преобразования данных. Например, строка '1234' может быть преобразована в целое, a 'abc' вызовет ошибку преобразования. Во время компиляции такая строка не может быть проанализирована и проверена.
- Delphi. Учимся на примерах - Сергей Парижский - Программирование
- Сделай видеоигру один и не свихнись - Слава Грис - Программирование / Руководства
- Психбольница в руках пациентов - Алан Купер - Программирование