Использование курсорных циклов FOR. Обработка курсоров с помощью циклов FOR в некоторых случаях значительно упрощает код программы. Цикл FOR с курсором – это цикл, связанный с курсором, явно заданным или пред- ставленным в виде оператора SELECT непосредственно в цикле.
Перепишем предыдущий пример с использованием курсоров FOR:
-- Изменение заработной платы сотруднику с курсорным циклом FOR DECLARE
-- отдел IT
vdep departments.department_id%TYPE := 60;
-- % повышения (снижения) заработной платы
pctsal NUMBER (5, 2) := 30;
newsal employees.salary%TYPE; BEGIN
FOR listemp IN (SELECT emp.employee_id, emp.job_id, emp.salary, jobs.min_salary, jobs.max_salary FROM employees emp, jobs WHERE department_id = vdep AND emp.job_id = jobs.job_id)
LOOP newsal := listemp.salary * (100 + pctsal) / 100;
IF newsal < listemp.min_salary THEN newsal := listemp.min_salary; ELSIF newsal > listemp.max_salary THEN newsal := listemp.max_salary; END IF;
DBMS_OUTPUT.put_line ( 'Cотрудник '
|| listemp.employee_id
|| ' старая заработная плата ='
|| listemp.salary
|| ' новая заработная плата ='
|| ' = '|| newsal);
END LOOP;
END;
/
В курсорном цикле FOR автоматически объявляется переменная или запись, с помощью которой можно считывать записи, курсор не нужно явно открывать и закрывать. Закрывается курсор сам, когда из него выбирается последняя строка.
Обработка исключительных ситуаций. В программах PL/SQL подпро- граммы обработки ошибок представляют собой обработчики исключительных ситуаций EXCEPTION. Как только инициируется исключение, нормальная ра- бота программы прерывается и управление передается в блок обработки ис- ключений. Поэтому важно помнить, что когда при проектировании программ необходимо перехватить и обработать исключение, не заканчивая на этом рабо- ту основной программы, необходимо пользоваться вложенными блоками.
Для того чтобы перехватить исключение, необходимо написать для него обработчик. В одном разделе EXCEPTION может быть написано несколько об- работчиков. По структуре они напоминают оператор CASE и имеют следую- щий синтаксис:
EXCEPTION
WHEN исключение_1 THEN
обработка_ исключения_1_исполняемые_операторы WHEN исключение_2 THEN
обработка_ исключения_2_исполняемые_операторы
. . .
WHEN исключение_n THEN
обработка_ исключения_n_исполняемые_операторы
[ WHEN OTHERS THEN
обработка_прочих_исключений_исполняемые_операторы ] END;
Также возможен вариант объединения нескольких исключений в одном обработчике. Например:
WHEN NO_DATA_FOUND OR ZERO_DIVIDE THEN
Если для инициированного исключения не найдено ни одного обработчи- ка, но при этом присутствует обработчик WHEN OTHERS, то его обработка выполняется именно в этом блоке. Если исключение все же не было обработа- но, то PL/SQL возвращает исключение в вызвавшую родительскую программу или же в ту среду, из которой была запущена программа. Это может быть SQL*Plus, TOAD или любое другое клиентское приложение.
Исключения бывают двух видов:
определенные программистом (user-defined exception);
системные, например, нехватка памяти или нарушение целостности БД. Исключения, определяемые программистом, объявляются в блоке декла-
рации, там же, где объявляются переменные и курсоры. Например:
DECLARE
vjob_id jobs.job_id%TYPE :='0'; exp_badempid EXCEPTION; BEGIN
NULL; END;
/
Область действия объявленных исключений аналогична области действия переменных и курсоров.
Системные исключения генерируются системой и, как правило, выдаются в формате
ORA-номер_ошибки сообщение_об_ошибке
Некоторые из системных исключений имеют имена – это так называемые предопределенные исключения. Список таких исключений приведен в прил. 4 (табл. П.4.1). Например, программа распознает исключительную ситуацию NO_DATA_FOUND в случае, если в результирующем множестве оператора SELECT INTO нет строк; исключительную ситуацию TOO_MANY_ROWS – если в результирующем множестве этого оператора более одной строки; ис- ключительную ситуацию DUP_VAL_ON_INDEX (повторяющееся значение в индексе) – если оператор INSERT или UPDATE дублирует ключевое значение, уже находящееся в таблице.
При обработке исключений запоминать номера ошибок бывает затрудни- тельно. Поэтому в PL/SQL имеется механизм связывания номера ошибки с его названием с помощью директивы компилятору – предопределенной прагмы EXCEPTION_INIT, сообщающей компилятору имя исключения, которое ассоци- ируется с конкретным кодом ошибки Oracle. Это позволяет обращаться к любо- му внутреннему исключению по имени, написав для него специальный обработ- чик. Прагма EXCEPTION_INIT указывается в декларативной части блока, под- программы или пакета PL/SQL c использованием следующего синтаксиса:
PRAGMA EXCEPTION_INIT (имя_исключения, код_ошибки_Oracle);
где имя_исключения – это имя исключения, ранее уже объявленного в этом блоке.
Пусть программа в качестве аргумента принимает цифровое значение в виде символьной строки и переводит его в числовой формат. Выполним этот блок в SQL*Plus.
DECLARE
vals VARCHAR2 (10) := :S;
valn NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE ('строка ='||vals); valn := TO_NUMBER (vals); DBMS_OUTPUT.PUT_LINE ('число ='||valn); END;
/
При выполнении получим приглашение для ввода параметра S и введем, например, число 123.36, в результате получим:
строка = 123.36
число = 123.36 Statement processed.
Когда пользователь задает аргумент в правильном формате (т. е. пригод- ном для конвертирования в число), программа отрабатывает нормально. Но стоит ввести неверно заданный аргумент, например, 123/36, то получим
ORA-06502: PL/SQL: numeric or value error: character to number conversion error Хорошим стилем программирования является обработка подобных ситу-
аций на этапе написания программного кода, в данном случае воспользуемся
прагмой EXCEPTION_INIT.
DECLARE
vals VARCHAR2 (10) := :S;
valn NUMBER; expChar_To_number EXCEPTION;
PRAGMA EXCEPTION_INIT (expChar_To_number, -06502); BEGIN
DBMS_OUTPUT.put_line ('строка =' || vals); valn := TO_NUMBER (vals); DBMS_OUTPUT.PUT_LINE ('число =' || valn); EXCEPTION
WHEN expChar_To_number THEN
DBMS_OUTPUT.PUT_LINE ('ошибка: аргумент ' || vals || ' не является числом');
END;
/
Инициирование исключений. Ссылаться на исключения можно несколь- кими способами.
При помощи оператора RAISE:
RAISE [имя_пакета].имя_исключения; или просто:
RAISE;
Первый вариант используется для инициирования объявленных в теку- щем блоке или в пакете исключений либо для инициирования системных ис- ключений по имени.
Второй вариант используется тогда, когда в блоке EXCEPTION необхо- димо повторно инициировать исключение.
1. Oracle предоставляет возможность инициировать исключения при по- мощи процедуры RAISE_APPLICATION_ERROR, которая в отличие от опера- тора RAISE позволяет связать с номером исключений сообщение об ошибке и не требует заранее определенного исключения:
RAISE_APPLICATION_ERROR (номер_ошибки, сообщение_об_ошибке);
где номер_ошибки – это целое число в пользовательском диапазоне от –20 999 до – 20 000; сообщение_об_ошибке – строка, длина которой не превышает 2048 символов.
При обработке исключений в ветке WHEN OTHERS обработчику иногда необходимо идентифицировать возникающую ошибку. Для этого имеются встро- енные функции SQLCODE и SQLERRM. Функция SQLCODE возвращает номер
текущей ошибки (0 указывает, что в стеке нет ни одной ошибки). Функция SQLERRM возвращает текстовое сообщение о текущей или указанной разработ- чиком ошибке. Для исключений, определяемых пользователем, SQLCODE воз- вращает 1, a SQLERRM возвращает «User-defined Exception» (определенное поль- зователем исключение). Максимальная длина строки, возвращаемой SQLERRM, составляет 512 байт. Значения функций SQLCODE и SQLERRM сначала присваи- ваются локальным переменным, и только потом эти переменные указываются в SQL-операторе. Например, эти функции часто используются для сохранения в до- полнительной таблице сведений об ошибках (протоколирование):
CREATE TABLE errors (num number, msg varchar2(256));
DECLARE
b number;
err_num NUMBER; err_msg CHAR (100); BEGIN
b := 2/0; EXCEPTION
WHEN OTHERS THEN err_num := SQLCODE; err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO errors VALUES (err_num, err_msg); END;
/
В примере переменная err_msg ограничена 100 символами. Если текст со- общения об ошибке превышает 100 символов, операция err_msg := SQLERRM; сама вызывает стандартную исключительную ситуацию VALUE_ERROR. Во избежание этого используется встроенная функция SUBSTR, обеспечивающая присваивание переменной v_ErrorText не более чем 100 символов.
При обработке ошибок можно не только выдавать приемлемые для поль- зователя сообщения об ошибках, вести протоколирование, но и просто их игно- рировать.
DECLARE
vals VARCHAR2 (10) := :S; valn NUMBER :=0;
BEGIN BEGIN
-- смогли конвертировать без ошибок valn := TO_NUMBER (vals); EXCEPTION
WHEN OTHERS THEN
-- игнорируем ошибку конвертации
NULL; END;
DBMS_OUTPUT.PUT_LINE ('строка =' || vals); DBMS_OUTPUT.PUT_LINE ('число =' || valn); END;
/
Получим результат:
строка =123/36 число =0
Хранимые процедуры и функции. Хранимые процедуры и функции в от- личие от анонимных блоков сохраняются в базе данных и наряду с таблицами, представлениями и другими структурными единицами являются самостоятель- ными объектами БД Oracle. Процедуры и функции сохраняются в откомпили- рованном виде и по мере их вызова загружаются в разделяемый пул, поддержи- ваемый СУБД, откуда удаляются по мере заполнения пула в порядке частоты использования кода процедуры или функции. Наиболее редко используемый код удаляется раньше и при очередном вызове снова загружается в пул с диска. Такая организация способствует производительности выполнения вызываемых процедур и функций, поскольку исключает постоянную загрузку с диска ис- полняемого кода.
Достарыңызбен бөлісу: |