□ CLOSE v_product_cursor;
Результат работы сценария совпадает с результатом сценария product_
cursor2 .sql.
Знакомство с программированием на PL/SQL 367
Несвязанные курсоры
Все курсоры в предыдущем разделе имели конкретный возвращаемый тип;
эти курсоры известны как связанные курсоры. Возвращаемый тип для связанного
курсора должен совпадать со столбцами в запросе, исполняемом
курсором. Несвязанный курсор не имеет возвращаемого типа и может исполнять
любой запрос.
Использование несвязанного курсора показано в следующем сценарии
unconstrained_cursor.sql. Обратите внимание, что v_cursor использован в
коде для выполнения двух различных запросов:
□ — Этот сценарий демонстрирует применение несвязанных курсоров
SET SERVEROUTPUT ON
DECLARE
- объявление типа REF CURSOR по имени t_ c u rs o r (не имеет возвращаемого
типа и может исполнять любой запрос)
TYPE t_ c u rso r IS REF CURSOR;
- объявление объекта типа t_ c u rs o r по имени v_cu rso r
v_cu rso r t_ cu rso r; - ~
- объявим объект для хранения столбцов из таблицы products
- по имени v_product (типа products%ROWTYPE)
v_product products%ROWTYPE;
- объявим объект для хранения столбцов из таблицы customers
- по имени v_customer (типа customers%ROWTYPE)
v_customer customers%ROWTYPE;
BEGIN
- назначим для v_cu rso r запрос и откроем его при помощи 0PEN-F0R
OPEN v_cu rso r FOR
SELECT * FROM products WHERE produ ct_id < 5;
- используем цикл для передачи строк из v_cu rso r в v_product
LOOP
FETCH v_cu rso r INTO v_product;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'p ro d u c t_ id = ' || v_ p ro d u ct.p rod u c t_ id ||
', name = ' || v_product.name ||
p r ic e = ' || v _ p ro d u c t.p ric e
);
END LOOP;
- назначим для v_cu rso r новый запрос и откроем его при помощи 0PEN-F0R
OPEN v_curso r FOR
SELECT * FROM customers WHERE customer_id < 3;
- используем цикл для передачи строк из v_cu rso r в v_product
LOOP
FETCH v_cu rso r INTO v_customer;
368 Глава 11
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(
'customer_id = ' || v_customer.customer_id ||
first_name = ' || v_customer.first_name ||
last_name = ' II v_customer.last_name
);
END LOOP;
- закроем v_cursor
CLOSE v_cursor;
END;
/
Для запуска сценария unconstrained_cursor.sql выполните команду:
□ SQL> @ «c:\SQL\unconstrained_cursor.sql»
Результат работы этого сценария выглядит следующим образом:
□ product_id = 1, name = Modern Science, price = 19.95
product_id = 2, name = Chemistry, price = 30
product_id = 3, name —Supernova, price = 25.99
product_id = 4, name = Tank War, price = 13.95
customer_id = 1, first_name = John, last_name = Brown
customer_id = 2, first_name = Cynthia, last_name = Green
Вы более подробно ознакомитесь с переменными REF CURSOR далее в
этой главе, а с пользовательскими типами - в следующей главе.
Исключения
Исключения используются для обработки ошибок исполнения в коде PL/
SQL. Выше был показан пример блока PL/SQL, содержащего блок
EXCEPTION:
□ DECLARE
v_width INTEGER;
v_height INTEGER := 2;
v_area INTEGER := 6;
BEGIN
— устанавливаем ширину равной площади, делённой на высоту
v_width := v_area / v_height;
DBMS_OUTPUT.PUT_LINE('v_width = ' || v _w id th ) ;
EXCEPTION
WHEN ZER0_DIVIDE THEN
DBMS _OU T PUT .PUT _ L INE ( 'Div is io n by z e r o ' ) ;
END;
/
Блок EXCEPTION в этом примере обрабатывает попытку деления на ноль.
В терминологии PL/SQL блок EXCEPTION ловит исключение ZER0_DIVIDE,
которое создаётся в блоке BEGIN (хотя вообще-то в коде примера ZER0_
Знакомство с программированием на PL/SQL 369
DIVIDE никогда не создаётся). Исключение ZERO_DIVIDE и другие часто используемые
исключения показаны в таблице 1 1 .1 .
Таблица 11.1. Предопределенные исключения
Исключение Ошибка Описание
ACCESS_INTO_ 0RA-06530
NULL
CASE_N0T_
POUND
0RA-06592
COLLECTION, 0RA-06531
IS_NULL
CURSOR, 0RA-06511
ALREADY_OPEN
DUP_VAL_0N_ 0RA-00001
INDEX
INVALID,
CURSOR
INVALID,
NUMBER
0RA-01001
0RA-01722
LOGIN,DENIED 0RA-01017
N0_DATA,F0UND 0RA-01403
N0T_L0GGED_0N 0RA-01012
PR0GRAM_ERR0R 0RA-06501
ROWTYPE, ORA-06504
MISMATCH
SELF_IS_NULL ORACLE-
30625
Была предпринята попытка назначить значения атрибутам
неинициализированного объекта (об объектах см. главу 12).
Не была выбрана ни одна из фраз WHEN оператора CASE, а
фраза e l s e отсутствует.
О коллекциях см. главу 13. Была сделана попытка применить
какие-то другие методы коллекции, кроме EXISTS, к
непроинициализированной вложенной таблице или к массиву
переменной длины, или была сделана попытка назначить
значения элементам непроинициализированной вложенной
таблицы или массива переменной длины.
Была сделана попытка открыть уже открытый курсор. Курсор
должен быть закрыт, прежде чем его можно будет заново
открыть.
Была сделана попытка записать повторяющееся значение в
столбец, для которого имеется ограничение по уникальности
и построен уникальный индекс.