7.2. Неявные курсоры
В последнем рассмотренном примере оператор, определяющий текущую среднюю сумму заказа, представляет собой обычный оператор SELECT, дополненный ключевым словом INTO. Это ключевое слово требуется для того, чтобы поместить возвращённые оператором значения в соответствующие переменные PL/SQL. В примере этими переменными являются CURRENT_AVG_SALES и A_PERFORM.CURRENT_SALES. Можно использовать данный оператор SELECT только при условии, что он возвращает не более одной записи. Если он вернет более одной записи, будет возбуждено исключение TOO_MANY_ROWS. Для этого оператора PL/SQL использует неявный курсор с именем "SQL". Курсор имеет атрибуты, к которым можно обратиться для получения информации о последней выполненной SQL-операции. Например, атрибут SQL%FOUND сообщит, выбрал ли последний оператор SELECT какие-нибудь записи. При наличии двух последовательных операторов SELECT информация в SQL%FOUND будет относиться только ко второму из них. Этим же атрибутом можно воспользоваться для проверки результатов добавления строки в таблицу:
DECLARE
quant NUMBER := 20;
BEGIN
INSERT INTO purchase
VALUES ('Medium Wodget', 'LN' , 48-AUG-02', quant);
IF (SQL%NOTFOUND)
THEN
dbms_output.put_line('Insert error?!');
END IF;
END;
/
SELECT * FROM purchase;
Для вставки значения в строку можно использовать переменную PL/SQL. При этом тип переменной должен либо совпадать с типом столбца, в котором предполагается хранить значение, либо допускать преобразование в тип столбца. Элементы данных SQL и PL/SQL могут взаимодействовать только при совпадении их типов.
Вставим две строки в таблицу PRODUCT, используя SQL-операторы,
INSERT INTO product
VALUES ('Large Harflinger' , 21, 100, '29-AUG-01') ;
INSERT INTO product
VALUES ('Round Snaphoo', 12, 144, '21-JUL-011);
SELECT * FROM product;
а затем обновим эту таблицу с помощью следующей процедуры PL/SQL:
CREATE OR REPLACE PROCEDURE update_prod (
prod_rec product%ROWTYPE
) IS
BEGIN
UPDATE product
SET last_stock_date = prod_rec.last_stock_date,
quantity_on_hand = quantity_on_hand + prod_rec.quantity_on_hand
WHERE product_name = prod_rec.product_name;
END update_prod;
/
DECLARE
a product%ROWTYPE;
BEGIN
a.product_name := 'Small Widget';
a.product_price := 87;
a.quantity_on_hand := 31; ,
a.last_stock_date := TO_DATE(' 12-NOV-07' );
update_prod (a) ;
END;
SELECT * FROM product;
При использовании DML-команд SQL в PL/SQL нужно учитывать все возможные исключения. Это особенно важно при использовании неявных курсоров, поскольку они не дают таких возможностей контроля, как явные курсоры.
Удаление также надо контролировать аналогично другим операциям. Например, при попытке удалить несуществующий товар это можно обнаружить с помощью SQL-атрибутов:
set serveroutput on
BEGIN
DELETE FROM product
WHERE product_name = 'junk';
IF (SQL%NOTFOUND)
THEN
dbms_output.put_line ( 'No such product');
END IF;
END;
/
Неявный курсор работает только с одной строкой данных, поэтому в тех случаях, когда связанный с курсором оператор может возвращать более одной строки результатов, следует использовать явный курсор. Кроме того, после обращения к явным курсорам они некоторое время остаются в памяти базы данных, и если будет введен тот же самый курсорный оператор SELECT, пока предыдущий находится в памяти, то результаты будет получен намного быстрее.
Курсор HISTORY_CUR примере из предыдущего раздела можно легко заменить неявным курсором, поскольку группирование записей по продавцам гарантирует получение только одной строки результатов.