Цикл FOR с курсором в PL/SQL Oracle
Курсорная форма цикла FOR связывается с явно заданным курсором (а по сути, определяется им) или инструкцией SELECT, заданной непосредственно в границах цикла. Используйте эту форму только в том случае, если вам нужно извлечь и обработать все записи курсора (впрочем, при работе с курсорами это приходится делать довольно часто).
Цикл FOR с курсором — одна из замечательных возможностей PL/SQL, обеспечивающая тесную и эффективную интеграцию процедурных конструкций с мощью языка доступа к базам данных SQL. Его применение заметно сокращает объем кода, необходимого для выборки данных из курсора, а также уменьшает вероятность возникновения ошибок при циклической обработке данных — ведь именно циклы являются одним из основных источников ошибок в программах.
Синтаксис цикла FOR с курсором
FOR запись IN { имя_курсора | (команда_SELECT) } LOOP исполняемые команды END LOOP;
Здесь запись — неявно объявленная запись с атрибутом %ROWTYPE для курсора имя_курсора.
Не объявляйте явно запись с таким же именем, как у индексной записи цикла. В этом нет необходимости, поскольку запись объявляется автоматически, к тому же это может привести к логическим ошибкам.
В цикле FOR можно также задать не курсор, а непосредственно SQL-инструкцию SELECT, как показано в следующем примере:
FOR book_rec IN (SELECT * FROM books) LOOP show_usage (book_rec); END LOOP;
Не рекомендуется использовать эту форму, поскольку встраивание инструкций SELECT в код затрудняет его сопровождение и отладку.
Свойства цикла FOR с использованием курсора
Свойство | Описание |
Условие завершения цикла | Выборка всех записей курсора. Цикл можно завершить и командой EXIT, но поступать так не рекомендуется |
Когда проверяется условие завершения цикла | После каждого выполнения тела цикла компилятор PL/SQL осуществляет выборку очередной записи. Если значение атрибута курсора %NOTFOUND% оказывается равным TRUE, цикл завершается. Если курсор не возвратит ни одной строки, тело цикла никогда не будет выполнено |
В каких случаях используется данный цикл | При необходимости выбрать и обработать каждую запись курсора |
Примеры цикла FOR с курсором
Допустим, необходимо обновить счета владельцев всех животных, живущих в специальном отеле. Следующий пример включает анонимный блок, в котором для выбора номера комнаты и идентификатора животного используется курсор occupancy_cur. Процедура update_bill вносит все изменения в счет:
DECLARE CURSOR occupancy_cur IS SELECT pet_id, room_number FROM occupancy WHERE occupied_dt = TRUNC (SYSDATE); occupancy_rec occupancy_cur%ROWTYPE; BEGIN OPEN occupancy_cur; LOOP FETCH occupancy_cur INTO occupancy_rec; EXIT WHEN occupancy_cur%NOTFOUND; update_bill (occupancy_rec.pet_id, occupancy_rec.room_number); END LOOP; CLOSE occupancy_cur; END;
Этот код последовательно и явно выполняет все необходимые действия: мы определяем курсор (строка 2), явно объявляем запись для этого курсора (строка 5), открываем курсор (строка 7), начинаем бесконечный цикл (строка 8), производим выборку записи из курсора (строка 9), проверяем условие выхода из цикла (конец данных) по атрибуту %NOTFOUND курсора (строка 10) и, наконец, выполняем обновление (строка 11). После этого программист должен закрыть курсор (строка 14).
Вот что получится, если переписать тот же код с использованием цикла FOR с курсором:
DECLARE CURSOR occupancy_cur IS SELECT pet_id, room_number FROM occupancy WHERE occupied_dt = TRUNC (SYSDATE); BEGIN FOR occupancy_rec IN occupancy_cur LOOP update_bill (occupancy_rec.pet_id, occupancy_rec.room_number); END LOOP; END;
Как все просто и понятно! Исчезло объявление записи. Исчезли команды OPEN, FETCH и CLOSE. Больше не нужно проверять атрибут %NOTFOUND. Нет никаких сложностей с организацией выборки данных. По сути, вы говорите PL/SQL: «Мне нужна каждая строка таблицы, и я хочу, чтобы она была помещена в запись, соответствующую курсору». И PL/SQL делает то, что вы хотите, как это должен делать любой современный язык программирования.
Курсору в цикле FOR, как и любому другому курсору, можно передавать параметры. Если какой-либо из столбцов списка SELECT определяется выражением, обязательно определите для него псевдоним. Для обращения к конкретному значению в записи курсора в пределах цикла необходимо использовать «точечный» синтаксис (имя_записи.имя_столбца — например, occupancy_rec.room_number), так что без псевдонима к столбцу-выражению обратиться не удастся.