LOOP文

ループ文は、一連の異なる値を使用して同じ文を反復実行します。

LOOP文は、次の3つの部分で構成されています。
  1. イテランド(ループ変数と呼ぶこともあります): ループ・ヘッダーからループ本体に値を渡します
  2. 繰返しコントロール: ループの値を生成します
  3. ループ本体: 値ごとに1回実行されます
loop_statement ::= [ iteration_scheme ] LOOP 
             loop_body 
END LOOP [ label ];

iteration_scheme ::= WHILE expression
                       | FOR iterator

ループ文には次のものがあります。

  • 基本LOOP

  • FOR LOOP

  • カーソルFOR LOOP

  • WHILE LOOP

ループを終了する文には次のものがあります。

  • EXIT

  • EXIT WHEN

現行のループの反復を終了する文には次のものがあります。

  • CONTINUE

  • CONTINUE WHEN

EXITEXIT WHENCONTINUEおよびCONTINUE WHENは、ループの内側の任意の場所に配置できますが、ループの外側に配置することはできません。ループの外側の文に制御を移してループを終了したりループの現行の反復を終了したりできるGOTO文のかわりに、これらの文を使用することをお薦めします。

例外が呼び出された場合もループは終了します。

LOOP文にはラベルを付けることができ、LOOP文をネストすることもできます。わかりやすさを向上させるために、ネステッド・ループにはラベルを付けることをお薦めします。END LOOP文のラベルと同じループ文の先頭のラベルが一致していることを確認する必要があります(コンパイラはチェックしません)。

関連項目:

基本LOOP文

基本LOOP文の構造は、次のとおりです。

ループが反復されるたびにstatementsが実行され、制御がループの先頭に戻ります。無限ループが発生しないように、文または例外の呼び出しによってループを終了する必要があります。

[ label ] LOOP
  statements
END LOOP [ label ];

関連項目:

「基本LOOP文」

FOR LOOP文の概要

FOR LOOP文では、ループ索引の値ごとに1つ以上の文を実行します。

FOR LOOPヘッダーでは、イテレータを指定します。イテレータでは、イテランドと繰返しコントロールを指定します。繰返しコントロールは、ループ本体内でアクセスするためのイテランドに値のシーケンスを提供します。ループ本体にある文は、イテランドの値ごとに1回実行されます。

次の繰返しコントロールを使用できます。

ステップ範囲: 段階的な数値のシーケンスを生成する繰返しコントロール。ステップが指定されていない場合、カウント制御はステップが1の正の整数型のステップ範囲になります。

単一式: 単一式を評価する繰返しコントロール。

繰返し式: 単一式を繰り返し評価する繰返しコントロール。

Values Of: コレクションからのすべての値を順番に生成する繰返しコントロール。このコレクションは、ベクトル値式、カーソル、カーソル変数または動的SQLのいずれかになります。

Indices Of: コレクションからのすべての索引を順番に生成する繰返しコントロール。Values Ofについて示したすべてのコレクション型が許容されますが、Indices Ofは、コレクションがベクトル変数のときに最も有効です。

Pairs Of: コレクションからのすべての索引と値のペアを生成する繰返しコントロール。Values Ofに許容されるすべてのコレクションがPairs Ofにも許容されます。Pairs Of繰返しコントロールには、2つのイテランドが必要になります。

カーソル: カーソル、カーソル変数または動的SQLからのレコードをすべて生成する繰返しコントロール。

FOR LOOP文の構造は、次のとおりです。

[ label ] for_loop_header 
  statements
END LOOP [ label ];

for_loop_header ::= FOR iterator LOOP

iterator ::= iterand_decl [, iterand_decl] IN iteration_ctl_seq 

iterand_decl  ::= pls_identifier [ MUTABLE | IMMUTABLE ] [ constrained_type ]          

iteration_ctl_seq ::= qual_iteration_ctl [,]...

qual_iteration_ctl ::= [ REVERSE ] iteration_control  pred_clause_seq

iteration_control ::= stepped_control 
                      | single_expression_control 
                      | values_of_control 
                      | indices_of_control 
                      | pairs_of_control  
                      | cursor_control 

pred_clause_seq ::= [ stopping_pred ] [ skipping_pred ]

stopping_pred ::= WHILE boolean_expression  

skipping_pred ::= WHEN boolean_expression 

stepped_control ::= lower_bound .. upper_bound [ BY step ]

single_expression_control ::= [ REPEAT ] expr

関連項目:

構文およびセマンティクスの詳細は、FOR LOOP文を参照してください

FOR LOOPのイテランド

FOR LOOP文の索引(イテランド)は、ループに対してローカルな変数として暗黙的または明示的に宣言します。

ループ内の文はイテランドの値を参照できますが、変更することはできません。ループの外側の文は、イテランドを参照できません。FOR LOOP文の実行後、イテランドは未定義になります。ループ・イテランドは、ループ・カウンタと呼ばれることもあります。

例5-10 索引値を変更しようとするFOR LOOP文

この例では、FOR LOOP文が索引の値を変更しようとしているため、エラーが発生します。

BEGIN
  FOR i IN 1..3 LOOP
    IF i < 3 THEN
      DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));
    ELSE
      i := 2;
    END IF;
  END LOOP;
END;
/

結果:

       i := 2;
       *
PLS-00363: expression 'I' cannot be used as an assignment target
ORA-06550: line 6, column 8:
PL/SQL: Statement ignored

例5-11 外側の文によるFOR LOOP文の索引の参照

この例では、FOR LOOP文の外側の文がループ索引を参照しようとしているため、エラーが発生します。

BEGIN
  FOR i IN 1..3 LOOP
    DBMS_OUTPUT.PUT_LINE ('Inside loop, i is ' || TO_CHAR(i));
  END LOOP;
  
  DBMS_OUTPUT.PUT_LINE ('Outside loop, i is ' || TO_CHAR(i));
END;
/ 

結果:

  DBMS_OUTPUT.PUT_LINE ('Outside loop, i is ' || TO_CHAR(i));
                                                         *
PLS-00201: identifier 'I' must be declared
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored

例5-12 変数と同じ名前を持つFOR LOOP文の索引

この例に示すように、FOR LOOP文の索引の名前が、外側のブロックで宣言された変数の名前と同じ場合、ローカルの暗黙的な宣言によって他の宣言が隠されます。

DECLARE
  i NUMBER := 5;
BEGIN
  FOR i IN 1..3 LOOP
    DBMS_OUTPUT.PUT_LINE ('Inside loop, i is ' || TO_CHAR(i));
  END LOOP;
  
  DBMS_OUTPUT.PUT_LINE ('Outside loop, i is ' || TO_CHAR(i));
END;
/

結果:

Inside loop, i is 1
Inside loop, i is 2
Inside loop, i is 3
Outside loop, i is 5

例5-13 FOR LOOP文による索引と同じ名前を持つ変数の参照

この例は、外側のブロックで宣言された変数をループの内側の文で参照できるように例5-12を変更する方法を示しています。

<<main>>  -- Label block.
DECLARE
  i NUMBER := 5;
BEGIN
  FOR i IN 1..3 LOOP
    DBMS_OUTPUT.PUT_LINE (
      'local: ' || TO_CHAR(i) || ', global: ' ||
      TO_CHAR(main.i)  -- Qualify reference with block label.
    );
  END LOOP;
END main;
/

結果:

local: 1, global: 5
local: 2, global: 5
local: 3, global: 5

例5-14 同じ索引名のネストしたFOR LOOP文

この例では、ネストしたFOR LOOP文の索引で同じ名前を使用しています。内部ループでは、外部ループのラベルで参照を修飾して、外部ループの索引を参照しています。また、内部ループでは、意味を明確にするために、それ自体のラベルでそれ自体の索引への参照も修飾しています。

BEGIN
  <<outer_loop>>
  FOR i IN 1..3 LOOP
    <<inner_loop>>
    FOR i IN 1..3 LOOP
      IF outer_loop.i = 2 THEN
        DBMS_OUTPUT.PUT_LINE
          ('outer: ' || TO_CHAR(outer_loop.i) || ' inner: '
           || TO_CHAR(inner_loop.i));
      END IF;
    END LOOP inner_loop;
  END LOOP outer_loop;
END;
/

結果:

outer: 2 inner: 1
outer: 2 inner: 2
outer: 2 inner: 3

イテランドの可変性

イテランドの可変性プロパティにより、ループ本体での代入を可能にするかどうかが決まります。

イテレータで指定したすべての繰返しコントロールがカーソル・コントロールの場合、イテランドはデフォルトで可変です。それ以外の場合、イテランドは不変です。イテランドのデフォルトの可変性プロパティは、イテランド変数の後ろにキーワードMUTABLEまたはIMMUTABLEを指定することで、イテランド宣言内で変更できます。

イテランドの可変を宣言する際の考慮事項は、次のとおりです。

  • Values Of繰返しコントロールのイテランドまたはPairs Of繰返しコントロールの値のイテランドに対する変更は、その繰返しコントロールで生成される値のシーケンスに影響しません。
  • ステップ範囲の繰返しコントロールまたは繰り返される単一式の繰返しコントロールのイテランドに変更を加えることが、そのコントロールの動作と生成される値のシーケンスに影響を与える可能性があります。
  • PL/SQLコンパイラは、イテランドを可変にすることで実行時のパフォーマンスに悪影響が現れる可能性を判断できます。また、それについての警告を報告することがあります。

複数の繰返しコントロール

複数の繰返しコントロールは、それらをカンマで区切って連鎖できます。

それぞれの繰返しコントロールには、制御式のセットがあります(一部のコントロールにはありません)。この式のセットは、コントロールの開始時に1回評価されます。これらの式の評価や評価された値をイテランドのタイプに変換することで、エラーが発生することがあります。この場合、ループが中断されて、通常の例外処理が発生します。イテランドは、繰返しコントロールのリストからアクセスできます。また、そのタイプのデフォルト値に初期設定されています。そのタイプにNOT NULL制約がある場合、最初の繰返しコントロールの制御式でのイテランドへの参照により、セマンティック・エラーが生成されます。これは、イテランドを暗黙的に初期化できないためです。ある繰返しコントロールがすべて処理されると、イテランドには、その繰返しコントロールの処理中に最後に代入された値が格納され、実行はその次の繰返しコントロールに進みます。イテランドに繰返しコントロールで値が代入されなかった場合は、その繰返しコントロールの開始前に保持していた値が維持されます。可変イテランドの最後の値がループ本体で変更されると、その変更された値は、後続の繰返しコントロールから制御式の評価時に参照できるようになります。

PL/SQLへの複数の繰返しコントロールの拡張

最初の繰返しコントロールが初期化されます。最初の繰返しコントロールのループが評価されます。その次の繰返しコントロールの制御式が評価されます。2番目の繰返しコントロールのループが評価されます。繰返しコントロールがなくなるまで、それぞれの繰返しコントロールとループが順番に評価されます。

例5-15 複数の繰返しコントロールの使用

この例は、ループ変数iが連続して3つの繰返しコントロールの値を取得することを示しています。イテレータの値は、デモ目的で出力されます。ループ制御が完全に消化された場合に次の繰返しコントロールが開始されることを示します。最後の繰返しコントロールが完全に消化されると、ループは完了します。

DECLARE
   i PLS_INTEGER;
BEGIN
   FOR i IN 1..3, REVERSE i+1..i+10, 51..55 LOOP
      DBMS_OUTPUT.PUT_LINE(i);
   END LOOP;
END;
/
結果:
1
2
3
13
12
11
10
9
8
7
6
5
4
51
52
53
54
55

ステップ範囲の繰返しコントロール

ステップ範囲の繰返しコントロールは数値のシーケンスを生成します。

制御式は、下限、上限およびステップです。

stepped_control ::= [ REVERSE ] lower_bound..upper_bound [ BY step ]
lower_bound ::= numeric_expression
upper_bound ::= numeric_expression
step ::= numeric_expression

PL/SQLへのステップ範囲の繰返しコントロールの拡張

繰返しコントロールの初期化時に、それぞれの制御式が評価されてイテランドのタイプに変換されます。Stepは、厳密に正の数値にする必要があります。制御式の評価中に例外が発生すると、ループが中断されて、通常の例外処理が発生します。ステップが指定されていない場合、ステップの値は1になります。ステップ範囲の繰返しコントロールによって生成される値は、ステップごとに下限から上限にまで達します。REVERSEが指定されていると、その値は上限から下限に向けてステップごとに減少します。イテランドが浮動小数点型の場合、ループ制御値の組合せによっては、丸め誤差のために無限ループが生成されることがあります。これについて報告するセマンティクス分析または動的分析はありません。イテランドが可変でありループ本体で変更されると、変更された値は、その次のイテランドの更新で増分とループ消化テストのために使用されます。これにより、ループで処理される値のシーケンスが変更されることがあります。

例5-16 FOR LOOP文の範囲繰返しコントロール

この例では、iterand ilower_boundは1、upper_boundは3です。このループは1から3の数値を出力します。

BEGIN
  FOR i IN 1..3 LOOP
     DBMS_OUTPUT.PUT_LINE (i);
  END LOOP;
END;
/

結果:

1
2
3

例5-17 反転FOR LOOP文の範囲繰返しコントロール

この例のFOR LOOP文では、3から1までの数値が出力されます。ループ変数iは、暗黙的にPLS_INTEGER (ループのカウントおよび索引付けのデフォルト)として宣言されます。

BEGIN
   FOR i IN REVERSE 1..3 LOOP
      DBMS_OUTPUT.PUT_LINE (i);
   END LOOP;
END;
/ 

結果:

3
2
1

例5-18 ステップ範囲の繰返しコントロール

この例は、明示的にNUMBER(5,1)として宣言されたループ変数nを示しています。カウンタの増分は0.5です。
BEGIN
   FOR n NUMBER(5,1) IN 1.0 .. 3.0 BY 0.5 LOOP
      DBMS_OUTPUT.PUT_LINE(n);
   END LOOP;
END;
/
結果:
1
1.5
2
2.5
3

例5-19 FOR LOOP文のSTEP句

この例では、FOR LOOPにより、実質的に索引が5ずつ増加します。

BEGIN
  FOR i IN 5..15 BY 5 LOOP
    DBMS_OUTPUT.PUT_LINE (i);
  END LOOP;
END;

結果:

5
10
15

例5-20 FOR LOOPのステップ範囲イテレータを使用した単純なステップ・フィルタ

この例では、単純なステップのフィルタを示します。このフィルタは、シグナル処理やリダクション・アプリケーションで使用されます。述語では、元のコレクションのK番目ごとの要素を作成対象のコレクションに渡すように指定しています。

FOR i IN start..finish LOOP
   IF (i - start) MOD k = 0 THEN
      newcol(i) := col(i)
   END IF;
END LOOP;  
  

ステップ・フィルタは、ステップ範囲イテレータを使用することで実装できます。

FOR i IN start..finish BY k LOOP
   newcol(i) := col(i)
END LOOP;

それと同じフィルタは、修飾式に埋め込んだステップ繰返しコントロールを使用して、新しいコレクションを作成することでも実装できます。

newcol := col_t(FOR I IN start..finish BY k => col(i));

単一式の繰返しコントロール

単一式の繰返しコントロールは、単一値を生成します。

single_expression_control ::= [ REPEAT ] expr

単一式の繰返しコントロールには、制御式はありません。

イテランドが可変のときに、ループ本体でイテランドを変更したことは、繰返しフォームで式を再評価するときに確認されます。

PL/SQLへの単一式の繰返しコントロールの拡張

式が評価され、その次の値を生成するためにイテランドのタイプに変換されます。停止述語があれば評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。スキップ述語があれば評価されます。TRUEに評価されない場合は、次のステップにスキップします。ループ本体を評価します。REPEATが指定されている場合、式が再度評価されます。それ以外の場合、繰返しコントロールは完全に消化されています。

例5-21 単一式の繰返しコントロール

この例は、1回処理されているループ本体を示しています。

BEGIN
   FOR i IN 1 LOOP
      DBMS_OUTPUT.PUT_LINE(i);
   END LOOP;
END;
/

結果:

1

この例では、イテランドが1で始まり、停止述語がtrueに評価されるまでi * 2が繰り返し評価されます。

BEGIN
   FOR i IN 1, REPEAT i*2 WHILE i < 100 LOOP
      DBMS_OUTPUT.PUT_LINE(i);
   END LOOP;
END;
/

結果:

1
2
4
8
16
32
64

コレクションの繰返しコントロール

VALUES OF、INDICES OFおよびPAIRS OF繰返しコントロールは、コレクションから導出されるイテランド用の値のシーケンスを生成します。

collection_iteration_control ::= values_of_control 
                                 | indices_of_control 
                                 | pairs_of_control 

values_of_control ::= VALUES OF expr 
                      | VALUES OF (cursor_object)
                      | VALUES OF (sql_statement)
                      | VALUES OF cursor_variable  
                      | VALUES OF (dynamic_sql) 

indices_of_control ::= INDICES OF expr 
                      | INDICES OF (cursor_object)
                      | INDICES OF (sql_statement)
                      | INDICES OF cursor_variable 
                      | INDICES OF (dynamic_sql)  

pairs_of_control ::= PAIRS OF expr 
                      | PAIRS OF (cursor_object) 
                      | PAIRS OF (sql_statement)
                      | PAIRS OF cursor_variable
                      | PAIRS OF (dynamic_sql) 
 

コレクション自体が制御式になります。このコレクションは、ベクトル値式、カーソル・オブジェクト、カーソル変数または動的SQLのいずれかになります。コレクションがnullの場合は、そのコレクションが定義されていて空であるものとして処理されます。

cursor_objectは、明示的なPL/SQLカーソル・オブジェクトです。sql_statementは、繰返しコントロールで直接指定したSQL文に応じて作成される暗黙的なPL/SQLカーソル・オブジェクトです。cursor_variableは、PL/SQL REF CURSORオブジェクトです。

VALUES OF繰返しコントロールのイテランドまたはVALUES OF繰返しコントロールの値イテランドがループ本体で変更されたとしても、そのような変更によって繰返しコントロールがその次に生成する値には影響しません。

ループ本体でコレクションが変更された場合の動作は不定です。ループ本体の実行中に、カーソル変数がイテランド以外からアクセスされた場合の動作は不定です。ほとんどのINDICES OF繰返しコントロールは、コレクションがベクトル変数でない場合に数列を生成します。

PL/SQLへのVALUES OF繰返しコントロールの拡張

コレクションは評価されてベクトルに代入されます。コレクションが空の場合は、繰返しコントロールが完全に消化されています。一時的な非表示索引が最初の要素(REVERSEが指定されている場合は最後の要素)の索引で初期化されます。イテランドのその次の値を生成するために、一時的な索引に基づいて値がコレクションからフェッチされます。停止述語があれば評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。スキップ述語があれば評価されます。TRUEに評価されない場合は、次のステップにスキップします。ループ本体を評価します。索引をベクトル内の次の要素(REVERSEの場合は前の要素)の索引に一時的に進めます。次の値を決定して、繰返しコントロールが完全に消化されるまで各イテランド値で再反復します。

例5-22 VALUES OF繰返しコントロール

この例では、コレクション・ベクトルの[11, 10, 34]からの値を出力します。繰返しコントロール変数iのイテランド値は、ベクトルの最初の要素、次の要素、および最後の要素の値です。


DECLARE
   TYPE intvec_t IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
   vec intvec_t := intvec_t(3 => 10, 1 => 11, 100 => 34);
BEGIN
   FOR i IN VALUES OF vec LOOP
      DBMS_OUTPUT.PUT_LINE(i);
   END LOOP;
END;
/

結果:

11 10 34

PL/SQLへのINDICES OF繰返しコントロールの拡張

コレクションは評価されてベクトルに代入されます。コレクションが空の場合は、繰返しコントロールが完全に消化されています。イテランドの次の値が決定されます(最初の要素の索引またはREVERSEが指定されている場合は最後の要素の索引)次の値がイテランドに代入されます。停止述語があれば評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。スキップ述語があれば評価されます。TRUEに評価されない場合は、次のステップにスキップします。ループ本体が評価されます。イテランドを次の値に進めます。この値は、ベクトル内の次の要素(REVERSEの場合は前の要素)の索引です。繰返しコントロールを完全に消化するまで、各イテランド値(次または前の要素の索引が代入された値)で再反復します。

例5-23 INDICES OF繰返しコントロール

この例では、コレクション・ベクトルの[1, 3, 100]の索引を出力します。繰返しコントロール変数iのイテランド値は、ベクトルの最初の要素、次の要素、および最後の要素の索引です。

DECLARE
   TYPE intvec_t IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
   vec intvec_t := intvec_t(3 => 10, 1 => 11, 100 => 34);
BEGIN
   FOR i IN INDICES OF vec LOOP 
       DBMS_OUTPUT.PUT_LINE(i);  
   END LOOP;
END;
/

結果:

1 3 100

PL/SQLへのPAIRS OF繰返しコントロールの拡張

コレクションは評価されてベクトルに代入されます。コレクションが空の場合は、繰返しコントロールが完全に消化されています。イテランドの次の索引値が決定されます(最初の要素の索引またはREVERSEが指定されている場合は最後の要素の索引)次の値で索引付けされた次の要素の値がイテランドに代入されます。停止述語があれば評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。スキップ述語があれば評価されます。TRUEに評価されない場合は、次のステップにスキップします。ループ本体が評価されます。イテランドを次の索引値に進めます。この値は、ベクトル内の次の要素(REVERSEの場合は前の要素)の索引です。繰返しコントロールが完全に消化されるまで各イテランド値で再反復します。

例5-24 PAIRS OF繰返しコントロール

この例では、コレクション・ベクトルをコレクション結果に反転し、結果の索引値のペア(10 => 3、11 => 1、34 => 100)を出力します。


DECLARE
   TYPE intvec_t IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
   vec  intvec_t := intvec_t(3 => 10, 1 => 11, 100 => 34);
   result intvec_t;
BEGIN
   result := intvec_t(FOR i,j IN PAIRS OF vec INDEX j => i);
   FOR i,j IN PAIRS OF result LOOP
      DBMS_OUTPUT.PUT_LINE(i || '=>'|| j);
   END LOOP;
END;
/
結果:

10=>3 11=>1 34=>100

カーソルの繰返しコントロール

カーソルの繰返しコントロールは、明示カーソルまたは暗黙カーソルによって返されるレコードのシーケンスを生成します。

カーソル定義が制御式になります。カーソルの繰返しコントロールでは、REVERSEは使用できません。

cursor_iteration__control ::=  { cursor _object
                    | sql_statement
                    | cursor_variable
                    | dynamic_sql }

cursor_objectは、明示的なPL/SQLカーソル・オブジェクトです。sql_statementは、繰返しコントロールで直接指定したSQL文に応じて作成される暗黙的なPL/SQLカーソル・オブジェクトです。cursor_variableは、PL/SQL REF CURSORオブジェクトです。カーソルの繰返しコントロールは、コレクションがカーソルであるときにVALUES OF繰返しコントロールと同じになります。ループ本体でイテランドが変更されていても、繰返しコントロールによって生成される次の値には影響がありません。コレクションがカーソル変数の場合はオープンされている必要があります。そうしていないと、例外が発生します。繰返しコントロールが完全に消化されたときにもオープンしたままになります。ループ本体の実行中に、カーソル変数がイテランド以外からアクセスされると動作は不定になります。

PL/SQLへのカーソルの繰返しコントロールの拡張

カーソルは、イテランドのベクトルを作成するために評価されます。ベクトルが空の場合は、繰返しコントロールが完全に消化されています。イテランドの次の値を作成するために、ベクトルで値がフェッチされます。停止述語があれば評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。スキップ述語があれば評価されます。TRUEに評価されない場合は、次のステップにスキップします。ループ本体を評価します。繰返しコントロールが完全に消化されるまでフェッチした各イテランド値で同じことを再反復します。

例5-25 カーソルの繰返しコントロール

この例では、表tのidからデータへの連想配列マッピングを作成します。
OPEN c FOR SELECT id, data FROM T;
FOR r rec_t IN c LOOP
   result(r.id) := r.data;
END LOOP;
CLOSE c;

繰返しコントロールでの動的SQLの使用

...
dynamic_sql ::= EXECUTE IMMEDIATE dynamic_sql_stmt [ using_clause ]

using_clause ::= USING [ [ IN ] (bind_argument [,])+ ]

動的SQLは、カーソルまたはコレクションの繰返しコントロールで使用されることがあります。このような構成では、デフォルトのタイプを指定できません。最初の繰返しコントロールとして使用する場合は、イテランド(またはPairs Ofコントロールの値イテランド)に明示的なタイプを指定する必要があります。using_clauseは、使用可能な唯一の句です。INTO句またはdynamic returning句は使用できません。指定したSQL文が行を返せない種類のものである場合は、通常のEXECUTE IMMEDIATE文でbulk collect into句またはinto句を指定したときと同じようなランタイム・エラーが報告されます。

例5-26 繰返しコントロールとしての動的SQLの使用

この例は、繰返しコントロールによる動的SQLからのすべてのレコードの生成を示しています。これにより、employee_idが103未満のすべての従業員のlast_nameおよびemployee_idを出力します。停止述語がTRUEの場合にループ本体が実行されます。

DECLARE
   cursor_str VARCHAR2(500) := 'SELECT last_name, employee_id FROM hr.employees ORDER BY last_name';
   TYPE rec_t IS RECORD (last_name VARCHAR2(25),
                         employee_id NUMBER);
BEGIN
   FOR r rec_t IN VALUES OF (EXECUTE IMMEDIATE cursor_str) WHEN r.employee_id < 103 LOOP
      DBMS_OUTPUT.PUT_LINE(r.last_name || ', ' || r.employee_id);
   END LOOP;
END;
/

結果:


Garcia, 102
King, 100
Yang, 101

例5-27 修飾式での繰返しコントロールとしての動的SQLの使用

v := vec_rec_t( FOR r rec_t IN (EXECUTE IMMEDIATE query_var) SEQUENCE => r); 

停止述語句とスキップ述語句

停止述語句により、繰返しコントロールを完全に消化できます。その一方、スキップ述語句により、いくつかの値についてループ本体をスキップできます。

これらの述語句内の式は、制御式ではありません。

停止述語句により、繰返しコントロールを完全に消化できます。boolean_expressionは、ループの各反復の最初に評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。

スキップ述語句により、いくつかの値についてループ本体をスキップできます。boolean_expressionが評価されます。TRUEに評価されない場合、繰返しコントロールは次の値にスキップします。

pred_clause_seq ::= [stopping_pred] [skipping_pred]

stopping_pred ::= WHILE boolean_expression  

skipping_pred ::= WHEN boolean_expression 

例5-28 FOR LOOP停止述語句の使用

この例では、WHILE停止述語句による繰返しコントロールを示します。繰返しコントロールは停止述語がTRUEに評価されなくなると完全に消化します。

BEGIN
   FOR power IN 1, REPEAT power*2 WHILE power <= 64 LOOP
      DBMS_OUTPUT.PUT_LINE(power);
   END LOOP;
END;
/

結果:

1
2
4
8
16
32
64

例5-29 FOR LOOPスキップ述語句の使用

この例では、述語句をスキップするWHEN句を使用した繰返しコントロールを示します。スキップする述語がTRUEに評価されない場合、繰返しコントロールは次の値にスキップします。

BEGIN
   FOR power IN 2, REPEAT power*2 WHILE power <= 64 WHEN MOD(power, 32)= 0 LOOP
      DBMS_OUTPUT.PUT_LINE(power);
   END LOOP;
END;
/

結果:

2
32
64

WHILE LOOP文

WHILE LOOP文は、条件がTRUEの場合に1つ以上の文を実行します。

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

[ label ] WHILE condition LOOP
  statements
END LOOP [ label ];

conditionがTRUEの場合は、statementsが実行され、ループの先頭に制御が戻り、そこでconditionが再度評価されます。conditionがTRUEでない場合は、WHILE LOOP文の後の文に制御が移ります。無限ループが発生しないように、ループ内の文で条件がFALSEまたはNULLになるようにする必要があります。構文の詳細は、「WHILE LOOP文」を参照してください。

EXITEXIT WHENCONTINUEまたはCONTINUE WHENstatements内に置くと、ループまたは現行のループの反復を途中で終了させることができます。

一部の言語は、条件をループの先頭ではなく最後でテストするLOOP UNTILまたはREPEAT UNTIL構造を持っているため、一連の文は1回以上実行されます。この構造をPL/SQLでシミュレートするには、EXIT WHEN文とともに基本LOOP文を使用します。

LOOP
  statements
  EXIT WHEN condition;
END LOOP;