4.3 順次制御文
sequential control statementsであるGOTO文とNULL文は、PL/SQLプログラミングではIF文やLOOP文ほど重要ではありません。
指定した文に移動するGOTO文が必要となることはほとんどありません。ただし、これを使用すると論理を単純化できる場合もあります。
何も実行しないNULL文には、条件文の意味とアクションを明確にすることによって、コードをわかりやすくする効果があります。
ここでのトピック
4.3.1 GOTO文
GOTO文は無条件に制御をラベルに移します。ラベルは有効範囲の中で他と重複しないもので、実行可能文かPL/SQLブロックの前に置かれている必要があります。GOTO文が実行されると、ラベルが付けられた文またはブロックに制御が移ります。GOTO文の制限については、「GOTO文」を参照してください。
GOTO文の使用は最小限にしてください(多用すると、コードの理解やメンテナンスが困難になります)。深いネスト構造から例外ハンドラに制御を移す場合、GOTO文は使用しないでください。かわりに、例外を呼び出してください。PL/SQLの例外処理メカニズムの詳細は、「PL/SQLのエラー処理」を参照してください。
ラベルは、ブロックの前(例4-21)または文の前(例4-29)にのみ置くことができます。例4-30のように文の途中に置くことはできません。
例4-30を修正する場合は、例4-31に示すように、NULL文を追加します。
GOTO文は、例4-32に示すように、カレント・ブロックから外側のブロックに制御を移すことができます。
このGOTO文は、参照されたラベルが置かれている最初の外側のブロックに制御を移しています。
例4-33では、GOTO文がIF文内に制御を移しているため、エラーが発生します。
例4-29 GOTO文
DECLARE
p VARCHAR2(30);
n PLS_INTEGER := 37;
BEGIN
FOR j in 2..ROUND(SQRT(n)) LOOP
IF n MOD j = 0 THEN
p := ' is not a prime number';
GOTO print_now;
END IF;
END LOOP;
p := ' is a prime number';
<<print_now>>
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n) || p);
END;
/
結果:
37 is a prime number
例4-30 不適切なラベル配置
DECLARE
done BOOLEAN;
BEGIN
FOR i IN 1..50 LOOP
IF done THEN
GOTO end_loop;
END IF;
<<end_loop>>
END LOOP;
END;
/
結果:
END LOOP; * ERROR at line 9: ORA-06550: line 9, column 3: PLS-00103: Encountered the symbol "END" when expecting one of the following: ( begin case declare exit for goto if loop mod null raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql run commit forall merge pipe purge
例4-31 GOTO文によるラベル付きのNULL文への移動
DECLARE
done BOOLEAN;
BEGIN
FOR i IN 1..50 LOOP
IF done THEN
GOTO end_loop;
END IF;
<<end_loop>>
NULL;
END LOOP;
END;
/
例4-32 GOTO文による外側のブロックへの制御の移動
DECLARE v_last_name VARCHAR2(25); v_emp_id NUMBER(6) := 120; BEGIN <<get_name>> SELECT last_name INTO v_last_name FROM employees WHERE employee_id = v_emp_id; BEGIN DBMS_OUTPUT.PUT_LINE (v_last_name); v_emp_id := v_emp_id + 5; IF v_emp_id < 120 THEN GOTO get_name; END IF; END; END; /
結果:
Weiss
例4-33 GOTO文によるIF文内への無効な制御の移動
DECLARE valid BOOLEAN := TRUE; BEGIN GOTO update_row; IF valid THEN <<update_row>> NULL; END IF; END; /
結果:
GOTO update_row; * ERROR at line 4: ORA-06550: line 4, column 3: PLS-00375: illegal GOTO statement; this GOTO cannot transfer control to label 'UPDATE_ROW' ORA-06550: line 6, column 12: PL/SQL: Statement ignored
4.3.2 NULL文
NULL文は、後続の文に制御を移すのみです。一部の言語では、このような命令をno-op(何もしない)と呼びます。
NULL文は、次のように使用できます。
-
GOTO文に対するターゲットとして使用できます(例4-31を参照)。 -
条件文の意味とアクションを明確にすることによって、わかりやすさを向上できます(例4-34を参照)。
-
プレースホルダおよびスタブ・サブプログラムを作成できます(例4-35を参照)。
-
考慮はするがアクションは必要ないことを示すことができます(例4-36を参照)。
例4-34では、NULL文によって、販売員のみがコミッションを受け取れることを明確にしています。
例4-35では、NULL文を使用してサブプログラムをコンパイルしています。実際の本体は、後で挿入できます。
ノート:
NULL文を使用する場合に警告が有効になっていると、unreachable codeという警告が発生する可能性があります。警告の詳細は、「コンパイル時の警告」を参照してください。
例4-36では、NULL文によって、A、B、C、D、F以外のgradeではアクションを起こさないことを示しています。
例4-34 アクションを実行しないことを明示するNULL文
DECLARE
v_job_id VARCHAR2(10);
v_emp_id NUMBER(6) := 110;
BEGIN
SELECT job_id INTO v_job_id
FROM employees
WHERE employee_id = v_emp_id;
IF v_job_id = 'SA_REP' THEN
UPDATE employees
SET commission_pct = commission_pct * 1.2;
ELSE
NULL; -- Employee is not a sales rep
END IF;
END;
/
例4-35 サブプログラム作成時のプレースホルダとしてのNULL文
CREATE OR REPLACE PROCEDURE award_bonus ( emp_id NUMBER, bonus NUMBER ) AUTHID DEFINER AS BEGIN -- Executable part starts here NULL; -- Placeholder -- (raises "unreachable code" if warnings enabled) END award_bonus; /
例4-36 単純なCASE文のELSE句でのNULL文
CREATE OR REPLACE PROCEDURE print_grade (
grade CHAR
) AUTHID DEFINER AS
BEGIN
CASE grade
WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excellent');
WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Very Good');
WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Good');
WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('Fair');
WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Poor');
ELSE NULL;
END CASE;
END;
/
BEGIN
print_grade('A');
print_grade('S');
END;
/結果:
Excellent