На сегодня вы уже многое знаете о PL/SQL. Но очень многое еще впереди. Как и во всех языках программирования, в PL/SQL имеются операторы циклов. Их три основных типа:
Самый простой тип цикла в языке PL/SQL таков:
LOOP NULL; END LOOP /
Но использовать такой цикл нет смысла, да и для экземпляра БД это не безопасно. Для этого необходимо использовать определенные пути выхода из циклов. Их то же три:
Давайте рассмотрим пример с применением цикла LOOP EXIT WHEN. Запишем следующее:
DECLARE i NUMBER := 0; BEGIN LOOP -- start loop 1 i := i + 1; IF (i >= 100) THEN i := 0; EXIT; -- exit when i >= 0 END IF; END LOOP; -- end loop 1 LOOP -- start loop 2 i := i + 1; EXIT WHEN (i >= 100); -- exit when i >= 0 END LOOP; -- end loop 2-------- END; /
Получаем после исполнения:
SQL> DECLARE 2 i NUMBER := 0; 3 4 BEGIN 5 6 LOOP 7 i := i + 1; 8 IF (i >= 100) THEN 9 i := 0; 10 EXIT; 11 END IF; 12 END LOOP; 13 14 LOOP 15 i := i + 1; 16 EXIT WHEN (i >= 100); 17 END LOOP; 18 19 END; 20 / Процедура PL/SQL успешно завершена.
Видимых действий не было, но и ошибок то же! Первый цикл закончился после того как i стало равно 10. При этом оно получило значение 0 и произошел выход из цикла. Второй цикл применил вложенное предложение EXIT WHEN, что является более верным его использованием синтаксически. Тем не менее, применение условных операторов предполагает перед выходом из цикла проделать некоторые действия. Цикл LOOP EXIT WHEN END LOOP в последующем будет самым, часто используемым при построении конструкций курсоров. Рассмотрим еще одну разновидность вышеприведенного цикла:
DECLARE k NUMBER := 0; BEGIN WHILE (k < 10) LOOP k := k + 1; END LOOP; END; /
Получаем:
SQL> DECLARE 2 k NUMBER := 0; 3 4 BEGIN 5 6 WHILE (k < 10) LOOP 7 k := k + 1; 8 END LOOP; 9 10 END; 11 / Процедура PL/SQL успешно завершена.
Здесь в отличие от предыдущего цикла, действия выполняются до тех пор пока условие истинно. Если условие ложно, то цикл прекращается. Что хорошо видно из приведенного примера. В PL/SQL в конструкциях циклов нет такого, иногда полезного, оператора как CONTINUE, вследствие того, что выражение CONTINUE зарезервировано языком PL/SQL и используется для других целей. Но такую конструкцию как CONTINUE можно эмулировать, применив цикл вида LOOP EXIT WHEN END LOOP и используя весьма не популярный, но в данном случае очень полезный оператор GOTO!
Запишем следующее, выведем все нечетные числа до 20:
SET SERVEROUTPUT ON DECLARE s NUMBER := 0; BEGIN DBMS_OUTPUT.enable; LOOP IF(MOD(s, 2) = 1) THEN GOTO LESS; END IF; DBMS_OUTPUT.put_line(TO_CHAR(s)||' is even!'); <<LESS>> EXIT WHEN (s = 20); s := s + 1; END LOOP; END; /
Получаем:
SQL> SET SERVEROUTPUT ON SQL> DECLARE 2 s NUMBER := 0; 3 4 BEGIN 5 6 DBMS_OUTPUT.enable; 7 8 LOOP 9 IF(MOD(s, 2) = 1) THEN 10 GOTO LESS; 11 END IF; 12 DBMS_OUTPUT.put_line(TO_CHAR(s)||' is even!'); 13 <<LESS>> 14 EXIT WHEN (s = 20); 15 s := s + 1; 16 END LOOP; 17 18 END; 19 / 0 is even! 2 is even! 4 is even! 6 is even! 8 is even! 10 is even! 12 is even! 14 is even! 16 is even! 18 is even! 20 is even! 0 is even! 2 is even! 4 is even! 6 is even! 8 is even! 10 is even! 12 is even! 14 is even! 16 is even! 18 is even! 20 is even! Процедура PL/SQL успешно завершена.
В результате применения GOTO в теле цикла получаем не сложную и понятную логику работы. Теперь давайте рассмотрим, не менее полезный и очень популярный в PL/SQL цикл FOR. Он к стати очень удобен при работе с курсорами, но об этом чуть позднее. Запишем следующее:
BEGIN FOR i IN 1..100 LOOP NULL; END LOOP; END; / SQL> BEGIN 2 FOR i IN 1..100 LOOP 3 NULL; 4 END LOOP; 5 END; 6 / Процедура PL/SQL успешно завершена.
В данный момент FOR успешно ничего не делал аж сто раз! Итак, давайте рассмотрим его чуть ближе, IN как и в операторе SELECT задает диапазон значений итерации цикла, а ".." это как вы помните так называемый "оператор диапазона"! Вот так просто и ясно. Остальное уже знакомо. Замечу так же, что переменная цикла i является переменной только для чтения. По этому шаг цикла FOR изменить принудительно нельзя! Если это необходимо, то лучше применять цикл вида LOOP EXIT WHEN END LOOP! :) Теперь давайте поработаем с числами:
DECLARE s NUMBER := 0; BEGIN DBMS_OUTPUT.enable; FOR i IN 1..20 LOOP IF(MOD(i, 2) = 1) THEN DBMS_OUTPUT.put_line(TO_CHAR(i)||' is even!'); s := i; END IF; END LOOP; DBMS_OUTPUT.put_line('last odd number was '||TO_CHAR(s)); END; /
Получаем:
SQL> DECLARE 2 s NUMBER := 0; 3 4 BEGIN 5 DBMS_OUTPUT.enable; 6 FOR i IN 1..20 LOOP 7 IF(MOD(i, 2) = 1) THEN 8 DBMS_OUTPUT.put_line(TO_CHAR(i)||' is even!'); 9 s := i; 10 END IF; 11 END LOOP; 12 DBMS_OUTPUT.put_line('last odd number was '||TO_CHAR(s)); 13 END; 14 / 1 is even! 3 is even! 5 is even! 7 is even! 9 is even! 11 is even! 13 is even! 15 is even! 17 is even! 19 is even! last odd number was 19 Процедура PL/SQL успешно завершена.
Та же задачка, только с циклом FOR. Да, функция MOD возвращает остаток от деления чисел, как вы, наверное, уже догадались. Так же в операторе FOR есть возможность задавать обратный отсчет, ну, например, перед стартом или взрывом! :) Вот так:
BEGIN DBMS_OUTPUT.enable; FOR i IN REVERSE 1..10 LOOP DBMS_OUTPUT.put_line(TO_CHAR(i)||'-'); END LOOP; DBMS_OUTPUT.put_line('Blastoff!'); END; /
Получаем:
SQL> BEGIN 2 DBMS_OUTPUT.enable; 3 FOR i IN REVERSE 1..10 LOOP 4 DBMS_OUTPUT.put_line(TO_CHAR(i)||'-'); 5 END LOOP; 6 DBMS_OUTPUT.put_line('Blastoff!'); 7 END; 8 / 10- 9- 8- 7- 6- 5- 4- 3- 2- 1- Blastoff! Процедура PL/SQL успешно завершена.
Нолика не было, но бабахнуло! Вот такой достаточно богатый набор операторов циклов в языке PL/SQL! Надеюсь, вы научитесь с легкостью их применять при построении серверных приложений ваших БД! :)