条件付き選択文

条件付き選択文IFおよびCASEは、データ値の違いに応じて異なる文を実行します。

IF文は、条件に応じて、一連の1つ以上の文を実行またはスキップします。IF文には次の形式があります。

  • IF THEN

  • IF THEN ELSE

  • IF THEN ELSIF

CASE文を使用すると、一連の条件を基に、対応する文を選択して実行できます。CASE文には次の形式があります。

  • 単純なCASE文は、単一の式を評価して、複数の可能性のある値と比較します。

  • 検索CASE文は、複数の条件を評価して、最初にTRUEになる条件を選択します。

CASE文は、オプションごとにアクションが異なる場合に適しています。

IF THEN文

IF THEN文は、条件に応じて、一連の1つ以上の文を実行またはスキップします。

IF THEN文の構造は、次のとおりです。

IF condition THEN
  statements
END IF;

conditionがTRUEの場合、statementsが実行されますが、それ以外の場合、IF文は何も実行しません。

構文の詳細は、「IF文」を参照してください。

ヒント:

次のようなIF文の使用は避けてください。

IF new_balance < minimum_balance THEN
  overdrawn := TRUE;
ELSE
  overdrawn := FALSE;
END IF;

かわりに、BOOLEAN式の値をBOOLEAN変数に直接代入してください。

overdrawn := new_balance < minimum_balance;

BOOLEAN変数は、TRUEFALSENULLのいずれかです。次のようには記述しないでください:

IF overdrawn = TRUE THEN
  RAISE insufficient_funds;
END IF;

かわりに、次のように記述してください:

IF overdrawn THEN
  RAISE insufficient_funds;
END IF;

例5-1 IF THEN文

この例では、salesの値がquota+200より大きい場合にのみ、THENEND IFの間にある文が実行されます。

DECLARE
  PROCEDURE p (
    sales  NUMBER,
    quota  NUMBER,
    emp_id NUMBER
  )
  IS
    bonus    NUMBER := 0;
    updated  VARCHAR2(3) := 'No';
  BEGIN
    IF sales > (quota + 200) THEN
      bonus := (sales - quota)/4;
 
      UPDATE employees
      SET salary = salary + bonus 
      WHERE employee_id = emp_id;
 
      updated := 'Yes';
    END IF;
 
    DBMS_OUTPUT.PUT_LINE (
      'Table updated?  ' || updated || ', ' || 
      'bonus = ' || bonus || '.'
    );
  END p;
BEGIN
  p(10100, 10000, 120);
  p(10500, 10000, 121);
END;
/
 

結果:

Table updated?  No, bonus = 0.
Table updated?  Yes, bonus = 125.

IF THEN ELSE文

IF THEN ELSE文の構造は、次のとおりです。

IF condition THEN
  statements
ELSE
  else_statements
END IF;

conditionの値がTRUEの場合、statementsが実行されますが、それ以外の場合は、else_statementsが実行されます。

例5-3に示すように、IF文はネストできます。

構文の詳細は、「IF文」を参照してください。

例5-2 IF THEN ELSE文

この例では、salesの値がquota+200より大きい場合にのみ、THENELSEの間にある文が実行されます。それ以外の場合は、ELSEEND IFの間にある文が実行されます。

DECLARE
  PROCEDURE p (
    sales  NUMBER,
    quota  NUMBER,
    emp_id NUMBER
  )
  IS
    bonus  NUMBER := 0;
  BEGIN
    IF sales > (quota + 200) THEN
      bonus := (sales - quota)/4;
    ELSE
      bonus := 50;
    END IF;
 
    DBMS_OUTPUT.PUT_LINE('bonus = ' || bonus);
 
    UPDATE employees
    SET salary = salary + bonus 
    WHERE employee_id = emp_id;
  END p;
BEGIN
  p(10100, 10000, 120);
  p(10500, 10000, 121);
END;
/

結果:

bonus = 50
bonus = 125

例5-3 ネストしたIF THEN ELSE文

DECLARE
  PROCEDURE p (
    sales  NUMBER,
    quota  NUMBER,
    emp_id NUMBER
  )
  IS
    bonus  NUMBER := 0;
  BEGIN
    IF sales > (quota + 200) THEN
      bonus := (sales - quota)/4;
    ELSE
      IF sales > quota THEN
        bonus := 50;
      ELSE
        bonus := 0;
      END IF;
    END IF;
 
    DBMS_OUTPUT.PUT_LINE('bonus = ' || bonus);
 
    UPDATE employees
    SET salary = salary + bonus 
    WHERE employee_id = emp_id;
  END p;
BEGIN
  p(10100, 10000, 120);
  p(10500, 10000, 121);
  p(9500, 10000, 122);
END;
/

結果:

bonus = 50
bonus = 125
bonus = 0

IF THEN ELSIF文

IF THEN ELSIF文の構造は、次のとおりです。

IF condition_1 THEN
  statements_1
ELSIF condition_2 THEN
  statements_2
[ ELSIF condition_3 THEN
    statements_3
]...
[ ELSE
    else_statements
]
END IF;

IF THEN ELSIF文は、conditionがTRUEである最初のstatementsを実行します。残りの条件は評価されません。TRUEのconditionがない場合は、else_statements(存在する場合)が実行されますが、else_statementsも存在しない場合、IF THEN ELSIF文は何も実行しません。

単一のIF THEN ELSIF文は、論理的に等価なネストしたIF THEN ELSE文より理解しやすい文です。

-- IF THEN ELSIF statement

IF condition_1 THEN statements_1;
  ELSIF condition_2 THEN statements_2;
  ELSIF condition_3 THEN statement_3;
END IF;

-- Logically equivalent nested IF THEN ELSE statements

IF condition_1 THEN
  statements_1;
ELSE
  IF condition_2 THEN
    statements_2;
  ELSE
    IF condition_3 THEN
      statements_3;
    END IF;
  END IF;
END IF;

構文の詳細は、「IF文」を参照してください。

例5-4 IF THEN ELSIF文

この例では、salesの値が50000より大きい場合、1番目と2番目の条件のいずれもTRUEになります。ただし、1番目の条件がTRUEであるため、bonusには1500という値が代入され、2番目の条件はテストされません。bonusに値1500が代入された後、制御はDBMS_OUTPUT.PUT_LINEの起動に移ります。

DECLARE
  PROCEDURE p (sales NUMBER)
  IS
    bonus  NUMBER := 0;
  BEGIN 
    IF sales > 50000 THEN
      bonus := 1500;
    ELSIF sales > 35000 THEN
      bonus := 500;
    ELSE
      bonus := 100;
    END IF;
 
    DBMS_OUTPUT.PUT_LINE (
      'Sales = ' || sales || ', bonus = ' || bonus || '.'
    );
  END p;
BEGIN
  p(55000);
  p(40000);
  p(30000);
END;
/

結果:

Sales = 55000, bonus = 1500.
Sales = 40000, bonus = 500.
Sales = 30000, bonus = 100.

例5-5 単純なCASE文をシミュレートするIF THEN ELSIF文

この例では、IF THEN ELSIF文を多数のELSIF句とともに使用し、単一の値を多くの使用可能な値と比較しています。この目的では、単純なCASE文の方がより明確になります(例5-6を参照)。

DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';
  
  IF grade = 'A' THEN
    DBMS_OUTPUT.PUT_LINE('Excellent');
  ELSIF grade = 'B' THEN
    DBMS_OUTPUT.PUT_LINE('Very Good');
  ELSIF grade = 'C' THEN
    DBMS_OUTPUT.PUT_LINE('Good');
  ELSIF grade = 'D' THEN
    DBMS_OUTPUT. PUT_LINE('Fair');
  ELSIF grade = 'F' THEN
    DBMS_OUTPUT.PUT_LINE('Poor');
  ELSE
    DBMS_OUTPUT.PUT_LINE('No such grade');
  END IF;
END;
/
 

結果:

Very Good

単純なCASE文

単純なCASE文の構造は、次のとおりです。

CASE selector
WHEN { selector_value_1a | dangling_predicate_1a } 
	[, …, { selector_value_1n | dangling_predicate_1n }] THEN statements_1
WHEN { selector_value_2a | dangling_predicate_2a }
       [, …, { selector_value_2n | dangling_predicate_2n }] THEN statements_2
...
WHEN { selector_value_na | dangling_predicate_na }
       [, …, { selector_value_nn | dangling_predicate_nn }] THEN statements_n
[ ELSE
  else_statements ]
END CASE;

selectorは式です(通常は1つの変数)。各selector_valueはリテラルまたは式のいずれかです。dangling_predicateは、1つまたは複数のselector_valueのかわりに、またはこれらを組み合せて使用することもできます。(構文の詳細は、「CASE文」を参照してください。)

dangling_predicateは、左オペランドが欠落している通常の式です(例:, < 2)。dangling_predicateを使用すると、検索対象のCASE文を必要とするより複雑な比較が可能になります。

単純なCASE文では、selector_valueselectorと等しいか、dangling_predicatetrueである最初のstatementsが実行されます。残りの条件は評価されません。selectorと等しいselector_valueがなく、truedangling_predicateがない場合、else_statementsが存在する場合は、CASE文でそれらが実行されますが、存在しない場合は、事前定義済の例外CASE_NOT_FOUNDが発生します。

例5-6では、単純なCASE文を使用して、単一の値を多くの使用可能な値と比較しています。例5-6CASE文は、例5-5IF THEN ELSIF文と論理的に等価です。

ノート:

単純なCASE式と同様に、単純なCASE文の選択子の値がNULLの場合、その選択子がWHEN NULLによって一致することはありません(例3-51を参照)。かわりに、検索CASE文をWHEN condition IS NULLとともに使用します(例3-55を参照)。

例5-6 単純なCASE文

DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';

  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 DBMS_OUTPUT.PUT_LINE('No such grade');
  END CASE;
END;
/

結果:

Very Good

例5-7 Dangling Predicateを使用した単純なCASE文

DECLARE
  grade NUMBER;
BEGIN
  grade := '85';

  CASE grade
    WHEN < 0, > 100 THEN DBMS_OUTPUT.PUT_LINE('No such grade');
    WHEN > 89 THEN DBMS_OUTPUT.PUT_LINE('A');
    WHEN > 79 THEN DBMS_OUTPUT.PUT_LINE('B');
    WHEN > 69 THEN DBMS_OUTPUT.PUT_LINE('C');
    WHEN > 59 THEN DBMS_OUTPUT.PUT_LINE('D');
    ELSE DBMS_OUTPUT.PUT_LINE('F');
  END CASE;
END;
/

結果:

B

検索CASE文

検索CASE文の構造は、次のとおりです。

CASE
WHEN condition_1 THEN statements_1
WHEN condition_2 THEN statements_2
...
WHEN condition_n THEN statements_n
[ ELSE
  else_statements ]
END CASE;

検索CASE文は、conditionがTRUEである最初のstatementsを実行します。残りの条件は評価されません。TRUEのconditionがない場合、CASE文はelse_statements(存在する場合)を実行しますが、else_statementsも存在しない場合は、事前定義の例外CASE_NOT_FOUNDを呼び出します。(構文の詳細は、「CASE文」を参照してください。)

例5-8の検索CASE文は、例5-6の単純なCASE文と論理的に等価です。

例5-8例5-6のいずれの場合も、ELSE句をEXCEPTION部に置き換えることができます。例5-9は、例5-8と論理的に等価です。

例5-8 検索CASE文

DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';
  
  CASE
    WHEN grade = 'A' THEN DBMS_OUTPUT.PUT_LINE('Excellent');
    WHEN grade = 'B' THEN DBMS_OUTPUT.PUT_LINE('Very Good');
    WHEN grade = 'C' THEN DBMS_OUTPUT.PUT_LINE('Good');
    WHEN grade = 'D' THEN DBMS_OUTPUT.PUT_LINE('Fair');
    WHEN grade = 'F' THEN DBMS_OUTPUT.PUT_LINE('Poor');
    ELSE DBMS_OUTPUT.PUT_LINE('No such grade');
  END CASE;
END;
/

結果:

Very Good

例5-9 CASE文でのELSE句にかわるEXCEPTION

DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';
  
  CASE
    WHEN grade = 'A' THEN DBMS_OUTPUT.PUT_LINE('Excellent');
    WHEN grade = 'B' THEN DBMS_OUTPUT.PUT_LINE('Very Good');
    WHEN grade = 'C' THEN DBMS_OUTPUT.PUT_LINE('Good');
    WHEN grade = 'D' THEN DBMS_OUTPUT.PUT_LINE('Fair');
    WHEN grade = 'F' THEN DBMS_OUTPUT.PUT_LINE('Poor');
  END CASE;
EXCEPTION
  WHEN CASE_NOT_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('No such grade');
END;
/

結果:

Very Good