Выбрать главу

□ 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, к

непроинициализированной вложенной таблице или к массиву

переменной длины, или была сделана попытка назначить

значения элементам непроинициализированной вложенной

таблицы или массива переменной длины.

Была сделана попытка открыть уже открытый курсор. Курсор

должен быть закрыт, прежде чем его можно будет заново

открыть.

Была сделана попытка записать повторяющееся значение в

столбец, для которого имеется ограничение по уникальности

и построен уникальный индекс.