再帰的サブプログラム
再帰的サブプログラムは、自分自身を起動します。再帰はアルゴリズムを単純化する強力な手法です。
再帰的サブプログラムには、2つ以上の実行パス(再帰的起動に導く1つのパスと終了条件に導く1つのパス)が必要です。後者が存在しない場合、メモリーが足りなくなり、PL/SQLによって事前定義の例外STORAGE_ERROR
が呼び出されるまで、再帰が続きます。
例9-37では、ファンクションを使用してnの階乗(n!、1からnまでのすべての整数の積)に関する次の再帰定義を実装しています。
n! = n * (n - 1)!
例9-38では、ファンクションを使用してn番目のフィボナッチ数(n-1番目とn-2番目のフィボナッチ数の和)を戻しています。1番目と2番目のフィボナッチ数は、それぞれ0(ゼロ)と1です。
ノート:
例9-38のファンクションは、結果キャッシュの対象に適したファンクションです。詳細は、「結果がキャッシュされる再帰ファンクション」を参照してください。
サブプログラムの再帰的起動が行われるたびに、サブプログラムで宣言されている各項目のインスタンスと、実行される各SQL文が作成されます。
カーソルFOR
LOOP
文の内側か、OPEN
またはOPEN
FOR
文とCLOSE
文の間にある再帰的起動は、起動ごとに新しいカーソルをオープンします。そのため、オープン・カーソルの数が、データベース初期化パラメータOPEN_CURSORS
で設定されている制限を超える可能性があります。
例9-37 nの階乗(n!)を返す再帰ファンクション
CREATE OR REPLACE FUNCTION factorial ( n POSITIVE ) RETURN POSITIVE AUTHID DEFINER IS BEGIN IF n = 1 THEN -- terminating condition RETURN n; ELSE RETURN n * factorial(n-1); -- recursive invocation END IF; END; / BEGIN FOR i IN 1..5 LOOP DBMS_OUTPUT.PUT_LINE(i || '! = ' || factorial(i)); END LOOP; END; /
結果:
1! = 1 2! = 2 3! = 6 4! = 24 5! = 120
例9-38 n番目のフィボナッチ数を返す再帰ファンクション
CREATE OR REPLACE FUNCTION fibonacci ( n PLS_INTEGER ) RETURN PLS_INTEGER AUTHID DEFINER IS fib_1 PLS_INTEGER := 0; fib_2 PLS_INTEGER := 1; BEGIN IF n = 1 THEN -- terminating condition RETURN fib_1; ELSIF n = 2 THEN RETURN fib_2; -- terminating condition ELSE RETURN fibonacci(n-2) + fibonacci(n-1); -- recursive invocations END IF; END; / BEGIN FOR i IN 1..10 LOOP DBMS_OUTPUT.PUT(fibonacci(i)); IF i < 10 THEN DBMS_OUTPUT.PUT(', '); END IF; END LOOP; DBMS_OUTPUT.PUT_LINE(' ...'); END; /
結果:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ...