ГЛАВА 3


УПРАВЛЯЮЩИЕ СТРУКТУРЫ

One ship drives east and another drives west
With the selfsame winds that blow.
'Tis the set of the sails and not the gales
Which tells us the way to go.
Ella Wheeler Wilcox

(Кто едет на запад, а кто - на восток,
А ветер - один на всех.
Не ветер, а парус, ткани кусок,
Диктует твой путь и успех.
Элла Уилер Уилкокс)

Эта глава показывает, как структурировать поток управления через программу PL/SQL. Вы узнаете, как соединяются предложения с помощью простых, но мощных управляющих структур, каждая из которых имеет единственную точку входа и выхода. В совокупности, эти структуры позволяют обработать любую ситуацию. А их правильное использование естественно приводит к хорошо структурированной программе.

Обзор

Согласно ТЕОРЕМЕ О СТРУКТУРАХ, любая компьютерная программа может быть написана с использованием трех основных управляющих структур, показанных на рис.3-1. Эти структуры можно комбинировать любым способом, необходимым для решения данной проблемы.

Рис.3-1
Управляющие структуры

          ВЫБОР                      ИТЕРАЦИЯ        ПОСЛЕДОВАТЕЛЬНОСТЬ

            ▀                           ▀                   ▀
                                                          
      T ╝°°°≥°°°▐ F                 ╝°°°≥°°°▐ F         ╡°°°≥°°°≈
    ╡°°°▌       ÷°°°≈           ╡°°▌       ÷°°°≈       ▀       ▀
    ▀   ╚°°°°°°°∙   ▀           ▀   ╚°°° °°°∙   ▀       ≤°°° °°°╠
                              ▀        T     ▀           
╡°°°≥°°°≈       ╡°°°≥°°°≈       ▀   ╡°°°≥°°°≈   ▀       ╡°°°≥°°°≈
▀       ▀       ▀       ▀          ▀       ▀   ▀       ▀       ▀
≤°°° °°°╠       ≤°°° °°°╠       ▀   ≤°°° °°°╠   ▀       ≤°°° °°°╠
    ▀      ╡°≈      ▀           ▀              ▀           
    ≤°°°°°▄ │°°°°°╠           ≤°°°°°°°╠              ╡°°°≥°°°≈
           ≤ ╠                                          ▀       ▀
                                                       ≤°°° °°°╠
                                                            
Структура выбора проверяет условие и в зависимости от его истинности выбирает одну или другую последовательность предложений. УСЛОВИЕ - это любая переменная или выражение, возвращающее булевское значение (TRUE, FALSE или NULL). Структура итерации повторно выполняет последовательность предложений, пока условие остается истинным. Структура последовательности просто выполняет последовательность предложений в том порядке, в котором они встречаются.

Теперь взглянем на эти структуры ближе.

Условное управление: предложения IF

Часто бывает необходимо предпринять альтернативные действия в зависимости от обстоятельств. Предложение IF позволяет вам выполнить последовательность предложений условно. Это значит, что, будет выполнена эта последовательность или нет, зависит от значения условия. Есть три формы предложений IF: IF-THEN, IF-THEN-ELSE и IF-THEN-ELSIF.

IF-THEN

Простейшая форма предложения IF ассоциирует условие с последовательностью предложений, окружаемой ключевыми словами THEN и END IF (не ENDIF), как показано ниже:

        IF условие THEN
            ряд_предложений;
        END IF;
Последовательность предложений выполняется, только если условие дает TRUE. Если условие дает FALSE или NULL, то предложение IF ничего не делает. В любом случае, управление передается на следующее предложение. Пример:
        IF sales > quota THEN
            compute_bonus(emp_id);
            UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id;
        END IF;
Вы можете, если хотите, записывать короткие предложения IF в одну строку, например:
        IF x > y THEN high := x; END IF;

IF-THEN-ELSE

Вторая форма предложения IF добавляет ключевое слово ELSE, за которым следует альтернативная последовательность предложений:

        IF условие THEN
            ряд_предложений1;
        ELSE
            ряд_предложений2;
        END IF;
Последовательность предложений в фразе ELSE выполняется, только если условие дает FALSE или NULL. Таким образом, фраза ELSE гарантирует, что одна из последовательностей предложений будет выполнена. В следующем примере, первое или второе предложение UPDATE будет выполнено, когда условие соответственно истинно или ложно:
        IF trans_type = 'CR' THEN
            UPDATE accounts SET balance = balance + credit WHERE ...
        ELSE
            UPDATE accounts SET balance = balance - debit WHERE ...
        END IF;
Последовательности предложений, включаемые в фразы IF и ELSE, сами могут содержать предложения IF. Следовательно, предложения IF могут вкладываться друг в друга, как показывает следующий пример:
        IF trans_type = 'CR' THEN
            UPDATE accounts SET balance = balance + credit WHERE ...
        ELSE
            IF new_balance >= minimum_balance THEN
                UPDATE accounts SET balance = balance - debit WHERE ...
            ELSE
                RAISE insufficient_funds;
            END IF;
        END IF;

IF-THEN-ELSIF

Иногда вы хотите выбрать действие из нескольких взаимно исключающих альтернатив. Третья форма предложения IF использует ключевое слово ELSIF (не ELSE IF), чтобы ввести дополнительные условия:

        IF условие1 THEN
            ряд_предложений1;
        ELSIF условие2 THEN
            ряд_предложений2;
        ELSE
            ряд_предложений3;
        END IF;
Если первое условие дает FALSE или NULL, фраза ELSIF проверяет следующее условие. В предложении IF может быть сколько угодно фраз ELSIF; последняя фраза ELSE необязательна. Условия вычисляются по одному сверху вниз. Если любое условие даст TRUE, выполняется соответствующая последовательность предложений, и управление передается на следующее за IF предложение (без вычисления оставшихся условий). Если все условия дадут FALSE или NULL, выполняется последовательность предложений в фразе ELSE, если она есть. Рассмотрим следующий пример:
        IF sales > 50000 THEN
            bonus := 1500;
        ELSIF sales > 35000 THEN
            bonus := 500;
        ELSE
            bonus := 100;
        END IF;
        INSERT INTO payroll VALUES (emp_id, bonus, ...);
Если значение sales превышает 50000, истинны как первое, так и второе условия. Тем не менее, переменной bonus присваивается правильное значение 1500, потому что второе условие проверяться не будет, а управление сразу будет передано на предложение INSERT.

Советы

Избегайте неуклюжих предложений IF, подобных следующему примеру:

        DECLARE
            ...
            overdrawn  BOOLEAN;
        BEGIN
            ...
            IF new_balance < minimum_balance THEN
                overdrawn := TRUE;
            ELSE
                overdrawn := FALSE;
            END IF;
            ...
            IF overdrawn = TRUE THEN
                RAISE insufficient_funds;
            END IF;
        END;
Этот код игнорирует два полезных факта. Во-первых, значение булевского выражения можно непосредственно присваивать булевской переменной. Так, первое предложение IF можно заменить простым присваиванием:
        overdrawn := new_balance < minimum_balance;
Во-вторых, булевская переменная сама имеет значение TRUE либо FALSE. Поэтому условие во втором предложении IF можно упростить:
        IF overdrawn THEN ...
По мере возможности, используйте фразу ELSIF вместо вложенных предложений IF. При этом ваш код будет легче читать и понимать. Сравните следующие предложения IF:
        IF условие1 THEN              |        IF условие1 THEN
            предложение1;             |            предложение1;
        ELSE                          |        ELSIF условие 2 THEN
            IF условие2 THEN          |            предложение2;
                предложение2;         |        ELSIF условие3 THEN
            ELSE                      |            предложение3;
                IF условие3 THEN      |        END IF;
                    предложение3;     |
                END IF;               |
            END IF;                   |
        END IF;                       |
Эти предложения логически эквивалентны, но первое из них затемняет логику, тогда как второе проявляет ее.

Итеративное управление: Предложения LOOP и EXIT

Предложения LOOP позволяют выполнить последовательность предложений несколько раз. Есть три формы предложения LOOP: LOOP, WHILE-LOOP и FOR-LOOP.

LOOP

Простейшую форму предложения LOOP представляет основной (или бесконечный) цикл, который окружает последовательность предложений между ключевыми словами LOOP и END LOOP:

        LOOP
            ряд_предложений
        END LOOP;
При каждой итерации цикла последовательность предложений выполняется, а затем управление передается на начало цикла. Если дальнейшее повторение нежелательно или невозможно, вы можете использовать предложение EXIT, чтобы закончить цикл. Вы можете поместить сколько угодно предложений EXIT внутри цикла, но только не вне цикла. Есть две формы предложения EXIT: EXIT и EXIT WHEN.

EXIT

Предложение EXIT форсирует безусловное завершение цикла. Когда встречается предложение EXIT, цикл немедленно заканчивается, и управление передается на следующее (за END LOOP) предложение. Пример:

        LOOP
            ...
            IF ... THEN
                ...
                EXIT;  -- немедленно выходит из цикла
            END IF;
        END LOOP;
        -- управление передается сюда
Как показывает следующий пример, вы не можете использовать предложение EXIT, чтобы завершить блок PL/SQL:
        BEGIN
            ...
            IF ... THEN
                ...
                EXIT;  -- незаконно
            END IF;
        END;
Не забывайте, что предложение EXIT можно применять только внутри цикла. Чтобы выйти из блока PL/SQL до достижения его нормального конца, можно использовать предложение RETURN (см. главу 9).

EXIT-WHEN

Предложение EXIT-WHEN позволяет завершить цикл условно. Когда встречается это предложение, вычисляется условие в фразе WHERE. Если это условие дает TRUE, цикл завершается, и управление передается на предложение, следующее за циклом. Пример:

        LOOP
            FETCH c1 INTO ...
            EXIT WHEN c1%NOTFOUND;  -- выйти из цикла при условии
            ...
        END LOOP;
        CLOSE c1;
Пока условие не станет истинным, цикл не может завершиться. Поэтому, предложения внутри цикла должны изменять значение условия. В последнем примере, если предложение FETCH извлекает строку, условие дает FALSE. Когда предложение FETCH не сможет возвратить строку, условие даст TRUE, цикл завершится, и управление будет передано на предложение CLOSE.

Предложение EXIT-WHEN заменяет простое предложение IF. Например, сравните следующие предложения:

        IF count > 100 THEN          |          EXIT WHEN count > 100;
            EXIT;                    |
        END IF;                      |
Эти предложения логически эквивалентны, но предложение EXIT-WHEN легче читается и понимается.

Метки циклов

Как и блоки PL/SQL, циклы могут иметь метки. Метка, необъявляемый идентификатор в двойных угловых скобках, должна появиться в начале предложения LOOP:

        <<имя_метки>>
        LOOP
            ряд_предложений
        END LOOP;
Имя метки цикла может также (необязательно) появиться в конце цикла в предложении END LOOP, как показывает следующий пример:
        <>
        LOOP
            ...
        END LOOP my_loop;
Когда вы используете вложенные циклы, конечные метки циклов улучшают читабельность программы.

Обе формы предложения EXIT позволяют выйти не только из текущего цикла, но из любого окружающего цикла. Просто дайте метку тому циклу, который вы хотите завершить, а затем укажите эту метку в предложении EXIT:

        <>
        LOOP
            ...
            LOOP
                ...
                EXIT outer WHEN ...  -- выйти из обоих циклов
            END LOOP;
            ...
        END LOOP outer;
Выход осуществляется из всех окружающих циклов, вплоть до того, чья метка специфицирована в предложении EXIT.

WHILE-LOOP

Предложение WHILE-LOOP ассоциирует условие с последовательностью предложений, окруженной ключевыми словами LOOP и END LOOP:

        WHEN условие LOOP
            ряд_предложений;
        END LOOP;
Перед каждой итерацией цикла условие проверяется. Если оно дает TRUE, то последовательность предложений выполняется, и управление возвращается на начало цикла. Если условие дает FALSE или NULL, то цикл обходится, и управление передается на следующее предложение. Пример:
        WHILE total <= 25000 LOOP
            ...
            SELECT sal INTO salary FROM emp WHERE ...
            total := total + salary;
        END LOOP;
Число повторений цикла зависит от условия и неизвестно до тех пор, пока цикл не завершится. Поскольку условие проверяется в начале цикла, последовательность предложений может не выполниться ни разу. В последнем примере, если начальное значение переменной total окажется больше 25000, условие даст FALSE, и цикл будет обойден.

В некоторых языках имеется структура LOOP UNTIL или REPEAT UNTIL, которая проверяет условие не в начале, а в конце итерации цикла. Поэтому гарантируется хотя бы однократное выполнение тела цикла. В PL/SQL такой структуры нет, но вы легко можете ее смоделировать:

        LOOP
            ряд_предложений;
            EXIT WHEN булевское_выражение;
        END LOOP;
Чтобы гарантировать хотя бы однократное выполнение цикла WHILE, используйте в условии инициализированную булевскую переменную:
        done := FALSE;
        WHILE NOT done LOOP
            ряд_предложений;
            done := булевское_выражение;
        END LOOP;
Какое-то предложение внутри цикла должно присвоить булевской переменной новое значение. В противном случае вы получите бесконечный цикл. Например, следующие предложения LOOP логически эквивалентны: WHILE TRUE LOOP | LOOP ... | ... END LOOP; | END LOOP;

FOR-LOOP

В то время как число итераций цикла WHILE неизвестно до тех пор, пока цикл не завершится, для цикла FOR число итераций известно до того, как войти в цикл. Циклы FOR осуществляют свои итерации по заданному интервалу целых чисел. (Курсорные циклы FOR, которые повторяются по активному множеству курсора, обсуждаются в главе 4.) Этот интервал является частью СХЕМЫ ИТЕРАЦИЙ, которая окружается ключевыми словами FOR и LOOP. Синтаксис имеет следующий вид:

        FOR счетчик IN [REVERSE] нижняя_граница..верхняя_граница LOOP
            ряд_предложений;
        END LOOP;
Интервал вычисляется один раз, при первом входе в цикл, и больше не перевычисляется. Как показывает следующий пример, последовательность предложений выполняется один раз для каждого целого в заданном интервале. После каждой итерации выполняется приращение индекса цикла.
        FOR i IN 1..3 LOOP -- присваивает переменной i значения 1, 2, 3
            ряд_предложений;  -- будет выполнен три раза
        END LOOP;
Как показывает следующий пример, если нижняя граница интервала совпадает с верхней, цикл выполняется один раз: FOR i IN 3..3 LOOP -- присваивает переменной i значение 3 ряд_предложений; -- будет выполнен один раз END LOOP; По умолчанию индекс наращивается на 1 от нижней до верхней границы. Однако, если вы используете ключевое слово REVERSE, индекс будет изменяться в обратном направлении, от верхней границы к нижней, как показывает следующий пример. После каждой итерации индекс уменьшается на 1.
        FOR i IN REVERSE 1..3 LOOP -- присваивает переменной i 3, 2, 1
            ряд_предложений;  -- будет выполнен три раза
        END LOOP;
Тем не менее, и в этом случае вы записываете границы интервала в возрастающем (а не убывающем) порядке.

Внутри цикла FOR к индексу цикла можно обращаться как к константе. Поэтому индекс может встречаться в выражениях, но ему нельзя присваивать значений, как показывает следующий пример:

        FOR ctr IN 1..10 LOOP
            ...
            IF NOT finished THEN
                INSERT INTO ... VALUES (ctr, ...);  -- законно
                factor := ctr * 2;  -- законно
                ...
            ELSE
                ctr := 10;  -- незаконно
            END IF;
        END LOOP;

Схемы итераций

Границами интервала цикла могут быть литералы, переменные или выражения, но их значения должны быть целочисленными. Например, следующие схемы итераций законны:

        j IN -5..5
        k IN REVERSE first..last
        step IN 0..TRUNC(high/low) * 2
        code IN ASCII('A')..ASCII('J')
Как видите, нижняя граница не обязана быть равна 1. Однако приращение (или отрицательное приращение) счетчика цикла всегда равно 1. В некоторых языках существует фраза, с помощью которой можно задать другую величину приращения. Пример на языке BASIC:
        FOR J = 5 to 15 STEP 5  :REM присваивает J значения 5,10,15
            ряд_предложений  -- J имеет значения 5,10,15
        NEXT J
В PL/SQL такой структуры не существует, но вы можете легко смоделировать ее. Рассмотрим следующий пример:
        FOR j IN 5..15 LOOP  -- присваивает j значения 5,6,7,...
            IF MOD(j, 5) = 0 THEN  -- выбирает кратные 5
                ряд_предложений;  -- j имеет значения 5,10,15
            END IF;
        END LOOP;
Этот цикл логически эквивалентен предыдущему циклу BASIC. Внутри поседовательности предложений счетчик цикла будет иметь лишь значения 5, 10 и 15.

Вы можете предпочесть не столь элегантный, но более эффективный способ, показанный в следующем примере. Внутри последовательности предложений при каждом обращении к счетчику цикла его значение умножается на 5.

        FOR j IN 1..3 LOOP  -- присваивает j значения 1,2,3
            ряд_предложений;  -- вместо j обращаться к j*5
        END LOOP;

Динамические интервалы

PL/SQL позволяет определять интервал цикла динамически во время выполнения, как показывает следующий пример:

        SELECT COUNT(empno) INTO emp_count FROM emp;
        FOR i IN 1..emp_count LOOP
            ...
        END LOOP;
Значение emp_count неизвестно во время компиляции; предложение SELECT возвращает это значение во время выполнения.

Что произойдет, если вычисленная нижняя граница интервала окажется больше верхней? Как показывает следующий пример, последовательность предложений внутри цикла не будет выполняться, и управление будет передано на следующее за циклом предложение:

        -- limit получает значение 1
        FOR i IN 2..limit LOOP
            ряд_предложений;  -- не выполнится ни разу
        END LOOP;
        -- управление будет передано сюда

Правила сферы

Счетчик цикла определен только внутри цикла. Вы не можете обратиться к нему вне цикла. После выхода из цикла значение счетчика цикла не определено, как показывает следующий пример:

        FOR ctr IN 1..10 LOOP
            ...
        END LOOP;
        sum := ctr - 1;  -- незаконно
Вы не обязаны явно объявлять счетчик цикла, потому что он неявно объявляется как локальная переменная типа INTEGER. Как показывает следующий пример, это локальное объявление перекрывает любое глобальное объявление:
        DECLARE
            ctr  INTEGER;
        BEGIN
            ...
            FOR ctr IN 1..25 LOOP
                ...
                IF ctr > 10 THEN ...  -- обращается к счетчику цикла
            END LOOP;
        END;
Чтобы в этом примере обратиться к глобальной переменной ctr, вы должны использовать метку и квалифицированную ссылку:
        <
> DECLARE ctr INTEGER; BEGIN ... FOR ctr IN 1..25 LOOP ... IF main.ctr > 10 THEN ... --обращается к глоб.переменной END LOOP; END main;
Такие же правила сферы применимы к вложенным циклам FOR. Рассмотрим следующий пример. Оба счетчика циклов имеют одно и то же имя. Поэтому для того, чтобы обратиться из внутреннего цикла к счетчику внешнего цикла, вы должны использовать метку и квалифицированную ссылку:
        <>
        FOR step IN 1..25 LOOP
            FOR step IN 1..10 LOOP
                ...
                IF outer.step > 15 THEN ...
            END LOOP;
        END LOOP outer;

Использование предложения EXIT

Предложение EXIT позволяет завершить цикл FOR прежде времени. Например, следующий цикл нормально выполняется десять раз, но, как только предложение FETCH не сможет вернуть очередную строку, цикл будет завершен независимо от того, сколько раз он успел выполниться.

        FOT j IN 1..10 LOOP
            FETCH c1 INTO emp_rec;
            EXIT WHEN c1%NOTFOUND;
            ...
        END LOOP;
Предложение EXIT позволяет выйти не только из текущего цикла FOR, но из любого окружающего цикла. Просто дайте метку тому циклу, который вы хотите завершить, а затем укажите эту метку в предложении EXIT:
        <>
        FOR i IN 1..5 LOOP
            ...
            FOR j IN 1..10 LOOP
                FETCH c1 INTO emp_rec;
                EXIT outer WHEN c1%NOTFOUND;  -- выход из обоих циклов
                ...
            END LOOP;
        END LOOP outer;
        -- управление будет передано сюда

Последовательное управление: предложения GOTO и NULL

В отличие от предложений IF и LOOP, предложения GOTO и NULL не являются ключевыми в программировании на языке PL/SQL. Структура языка такова, что предложение GOTO требуется редко. Иногда его применение может быть оправдано некоторым упрощением логики. Предложение NULL может прояснить смысл условных предложений в программе и улучшить читабельность.

Предложение GOTO

Предложение GOTO выполняет безусловный переход к указанной метке. Метка должна быть уникальной в своей сфере, и должна предшествовать выполнимому предложению или блоку PL/SQL. Предложение GOTO передает управление на помеченное предложение или блок. В следующем примере управление передается на выполнимое предложение, находящееся дальше в последовательности предложений:

        BEGIN
            ...
            GOTO insert_row;
            ...
            <>
            INSERT INTO emp VALUES ...
        END;
В следующем примере управление передается на блок PL/SQL, расположенный выше в последовательности предложений:
        BEGIN
            ...
            <>
            BEGIN
                UPDATE emp SET ...
                ...
            END;
            ...
            GOTO update_row;
            ...
        END;
В следующем примере метка <> незаконна, потому что она стоит не перед выполнимым предложением:
        DECLARE
            done  BOOLEAN;
        BEGIN
            ...
            FOR i IN 1..50 LOOP
                IF done THEN
                    GOTO end_loop;
                END IF;
                ...
            <>  -- незаконно
            END LOOP;  -- это не выполняемое предложение
        END;
Чтобы исправить последний пример, просто добавьте за меткой предложение NULL:
        DECLARE
            done  BOOLEAN;
        BEGIN
            ...
            FOR i IN 1..50 LOOP
                IF done THEN
                    GOTO end_loop;
                END IF;
                ...
            <>
            NULL;  -- выполняемое предложение
            END LOOP;
        END;
Как показывает следующий пример, предложение GOTO может передать управление в окружающий блок из текущего блока:
        DECLARE
            my_ename  CHAR(10);
        BEGIN
            ...
            <>
            SELECT ename INTO my_ename FROM emp WHERE ...
            ...
            BEGIN
                ...
                GOTO get_name;  -- переход в окружающий блок
            END;
        END;
Предложение GOTO передает управление в первый из окружающих блоков, в котором встретится указанная метка.

Ограничения

Некоторые возможные назначения предложения GOTO незаконны. В частности, предложение GOTO не может передавать управление в предложение IF, в предложение LOOP или в подблок. Например, следующее предложение GOTO незаконно:

        BEGIN
            ...
            GOTO update_row;  -- незаконный переход в предложение IF
            ...
            IF valid THEN
                ...
                <>
                UPDATE emp SET ...
            END IF;
        END;
Далее, предложение GOTO не может передавать управление из одной фразы предложения IF в другую, как показывает следующий пример:
        BEGIN
            ...
            IF valid THEN
                ...
                GOTO update_row;  -- незаконный переход в фразу ELSE
            ELSE
                ...
                <>
                UPDATE emp SET ...
            END IF;
        END;
Следующий пример показывает, что предложение IF не может передавать управление из окружающего блока в подблок:
        BEGIN
            ...
            IF status = 'OBSOLETE' THEN
                GOTO delete_part;  -- незаконный переход в подблок
            END IF;
            ...
            BEGIN
                ...
                <>
                DELETE FROM parts WHERE ...
            END;
        END;
Кроме того, предложение GOTO не может передавать управление наружу из подпрограммы, как показывает следующий пример:
        DECLARE
            ...
            PROCEDURE compute_bonus (emp_id NUMBER) IS
            BEGIN
                ...
                GOTO update_row;  -- незаконный переход из подпрограммы
            END;
        BEGIN
            ...
            <>
            UPDATE emp SET ...
        END;
Наконец, предложение GOTO не может передавать управление из обработчика исключений в текущий блок. Например, следующее предложение GOTO незаконно:
        DECLARE
            ...
            pe_ratio  REAL;
        BEGIN
            ...
            SELECT price / NVL(earnings, 0) INTO pe_ratioo FROM ...
            <>
            INSERT INTO stats VALUES (pe_ratio, ...);
        EXCEPTION
            WHEN ZERO_DIVIDE THEN
                pe_ratio := 0;
                GOTO insert_row;  -- незаконный переход в текущий блок
            ...
        END;
Однако предложение GOTO может передавать управление из обработчика исключений в окружающий блок.

Советы

Чрезмерное применение предложений GOTO может привести к сложному, неструктурированному коду, который трудно понимать и сопровождать. Поэтому старайтесь использовать предложения GOTO пореже. Например, чтобы перейти из глубоко вложенной структуры на программу обработки ошибок, возбуждайте исключение, вместо того чтобы использовать предложение GOTO.

Предложение NULL

Предложение NULL явно специфицирует отсутствие действия; оно ничего не делает, и управление передается на следующее предложение. Оно, однако, может улучшить читабельность программы. В конструкте, допускающем альтернативные действия, предложение NULL используется для обозначения места действия. Оно напоминает читателю программы о том, что соответствующая альтернатива не была пропущена нечаянно, а просто не требует никакого действия. В следующем примере предложение NULL показывает, что для непоименованных исключений никакие действия не выполняются:

        ...
        EXCEPTION
            WHEN ZERO_DIVIDE THEN
                ROLLBACK;
            WHEN CALUE_ERROR THEN
                INSERT INTO errors VALUES ...
                COMMIT;
            WHEN OTHERS THEN
                NULL;
        END;
Каждая фраза в предложении IF должны содержать хотя бы одно выполнимое предложение. Предложение NULL помогает удовлетворить этому требованию. Поэтому вы можете использовать предложение NULL в фразах, соответствующих тем обстоятельствам, в которых никакий действий не требуется. В следующем примере предложение NULL подчеркивает, что премии получат лишь сотрудники с высоким рейтингом:
        IF rating > 90 THEN
            compute_bonus(emp_id);
        ELSE
            NULL;
        END IF;
Предложение NULL предоставляет также удобный способ создания "затычек" при разработке приложения сверху вниз. Затычки - это фиктивные подпрограммы, с помощью которых вы откладываете определения процедур и функций до тех пор, пока не проверите и не отладите главную программу. В следующем примере предложение NULL помогает удовлетворить тому требованию языка, что выполнимая часть подпрограммы должна содержать хотя бы одно предложение:
        PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS
        BEGIN
            NULL;
        END debit_account;