Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
33
Добавлен:
17.04.2018
Размер:
75.26 Кб
Скачать

Предложение where с условием поиска current of

Когда курсор открывается для обновления или удаления выбранных записей, можно использовать предложение

WHERE CURRENT OF имя_курсора

для доступа к таблице и строке, которые соответствуют последней записи, выбранной предложением WHERE оператора UPDATE или DELETE. Это демонстрируется в приведенном ниже коде, который снижает цены в таблице PRODUCT на 3%:

SELECT product_name, product_price

FROM product;

DECLARE

CURSOR product_cur IS

SELECT * FROM product

FOR UPDATE OF product_price;

BEGIN

FOR product_rec IN product_cur

LOOP

UPDATE product

SET product_price = (product_rec.product_price * 0.97)

WHERE CURRENT OF product_cur;

END LOOP;

END;

/

SELECT product_name, product_price

FROM product;

6.4. Использование вложенных циклов и курсоров

Приведенный ниже код создания процедуры является примером использования курсоров, а также циклов внутри циклов, т.е. вложенных циклов.

-- Эта процедура подсчитывает комиссионные продавцов.

-- Выводится код продавца, полное количество выполненных им продаж

-- и соответствующие комиссионные.

-- Входные данные: отсутствуют. Об ошибках не сообщается, исключения не активизируются.

/* Алгоритм: создается курсор для соединения таблиц PRODUCT и PURCHASE по столбцу PRODUCT_NAME. Результат упорядочивается по продавцам. Внешний цикл перебирает всех продавцов, а внутренний цикл обрабатывает все строки для одного продавца.

*/

CREATE OR REPLACE PROCEDURE do_commissions IS

commission_rate NUMBER := 2;

total_sale NUMBER := 0;

current_person CHAR(3) := ' ' ;

next_person CHAR(3) ;

quantity_sold NUMBER := 0 ;

item_price NUMBER := 0 ;

CURSOR sales_cur IS

SELECT tab1.salesperson,

tab1.quantity,

tab2.product_price

FROM purchase tab1, product tab2

WHERE tab1.product_name = tab2.product_name;

ORDER BY salesperson;

BEGIN

OPEN sales_cur;

LOOP

FETCH sales_cur INTO

next_person, quantity_sold, item_price;

WHILE (next_person = current_person

AND

sales_cur%FOUND)

LOOP

total_sale := total_sale + (quantity_sold * item_price);

FETCH sales_cur INTO

next_person, quantity_sold, item_price;

END LOOP;

IF (sales_cur%FOUND)

THEN

IF (current_person != next_person)

THEN

IF (current_person != ' ' )

THEN

dbms_output.put_line (current_person || ' ' || total_sale ||

' ' || total sale * commission_rate / 100);

END IF;

total_sale := quantity_sold * item_price;

current_person := next_person;

END IF;

ELSE IF (current_person != ' ')

THEN

dbms_output.put_line(current_person || ' ' || total_sale || ' ' ||

total_sale * commission_rate / 100);

END IF;

END IF;

EXIT WHEN sales_cur%NOTFOUND;

END LOOP;

CLOSE sales_cur;

END do_commissions;

/

Курсорный оператор SELECT, указанный в объявлении курсора, извлекает количество проданных товаров из таблицы PURCHASE, а их цены — из таблицы PRODUCT при помощи соединения по имени товара. Результат упорядочивается по продавцам, чтобы записи, относящиеся к отдельному продавцу, располагались вместе.

После открытия курсора и выборки первой строки проверяется условие WHILE. Поскольку текущий продавец в этот момент еще не определен и соответствующая переменная имеет значение по умолчанию (одиночный пробел), не совпадающее ни с одним из личных кодов, цикл пропускается и следует переход к первому оператору IF. Он проверяет, возвращала ли последняя команда FETCH какую-нибудь запись. Если запись была возвращена, значения current_person и next_person проверяются на совпадение. Если они не совпадают, последняя выборка относится к новому продавцу, т.е. пора распечатать комиссионные для текущего продавца. Следует обратить внимание, что первое значение current_person не входит в число допустимых, поэтому условие в третьем IF не выполняется и печать не производится.

Следующий оператор заносит в переменную total_sale цену самого первого товара. Затем значение next_person сохраняется в переменной current_person. После этого происходит возврат к оператору FETCH в начале цикла, поскольку условие выхода из цикла еще не выполнено. В результате выборки значение next_person может оказаться таким же, как и current_person, а это означает, что текущему продавцу соответствует более одной записи в списке продаж. В этом случае происходит вход в цикл WHILE и цена товара, умноженная на проданное количество, добавляется к общему объему продаж, выполненных данным продавцом. Выборка новых записей из курсора и суммирование цен продолжаются до тех пор, пока не будет идентифицирован новый продавец. Весь процесс повторяется снова и снова, пока не закончатся записи в курсоре. В этой точке значение current_person проверяется на допустимость. При положительном результате проверки самый последний оператор IF распечатывает объем продаж и комиссионные для этого продавца. Для расчета комиссионных используется константа commission_rate.

Чтобы протестировать эту процедуру, нужно ввести показанные ниже команды.

SELECT tab1.salesperson, tab1.quantity, tab2.product_price

FROM purchase tab1, product tab2

WHERE tab1.product_name = tab2.product_name

ORDER BY salesperson

;

EXECUTE do_commissions;

Первая команда выводит необработанные записи из таблицы PURCHASE, сцепленные с записями из таблицы PRODUCT, а вторая вызывает процедуру DO_COMMISSIONS для суммирования продаж, отраженных в этих записях, и расчета соответствующих комиссионных каждого продавца.

Соседние файлы в папке Lab5