Oracle PL/SQL入門


おすすめ書籍



PL/SQLについて

PL/SQL とはOracle社がOracle Databaseのためにデータベース問合せ言語である SQL を独自に拡張した手続き型プログラミング言語です。
PL/SQL を使うと SQL のみでは1回のデータ処理しかできないものを、その SQL の繰返しやデータの値による条件判断により きめ細かいデータ処理ができる様になります。

PL/SQL の基本的な構造は以下の様になります。
DECLARE の{変数、定数、カーソル等の宣言部}は無くてもいいのですが、この{処理実行部}で必要な変数等の宣言を行います。 BEGIN ... END; の{処理実行部}に実行させたい命令やSQL文等を記述します。
また、例外処理を行う場合には BEGIN ... END; の中に EXCEPTION を記述し EXCEPTION ... END; の間に{例外処理部}を記述します。

[DECLARE
    {変数、定数、カーソル等の宣言部}
]
BEGIN
    {処理実行部}
[EXCEPTION
    {例外処理部}
]
END;
([ ... ] は省略可を表す)

以下にSQLPLUS上で実行した PL/SQL の実行例を示します。 この例では、1個の変数を宣言し、実行部ではその変数に文字列を設定し DBMS_OUTPUT.PUT_LINE により標準出力への表示を行います。 その後、SQL文によりシステム日付の文字列化したものを変数に設定し、標準出力への表示を行います。

PL/SQL の実行の前にSET SERVEROUTPUT ON を行いますが、 これにより DBMS_OUTPUT.PUT_LINESQLPLUS上に表示される様にします。

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2      -- 変数宣言
  3      WORK VARCHAR2(32);
  4  BEGIN
  5      -- 単純に変数への設定
  6      WORK := '1234567890';
  7      DBMS_OUTPUT.PUT_LINE('TEST=' || WORK);
  8      -- 変数へシステム日付の設定
  9      SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD') INTO WORK FROM DUAL;
 10      DBMS_OUTPUT.PUT_LINE('DATE=' || WORK);
 11  END;
 12  /
TEST=1234567890
DATE=2018/12/13

PL/SQLプロシージャが正常に完了しました。

SQL>

宣言部(DECLARE)の変数などの宣言

データ型の変数宣言を行う場合は以下の様にします。変数名の後にデータ型を記述します。初期値がある場合は :=(コロン、イコール) で結びます。

    <変数名>    <データ型> [:= <初期値>];

各種のデータ型の変数宣言の例と、%TYPEを使った宣言及び、カーソル宣言の例を以下に記します。

%TYPEを使った宣言はテーブルのカラム名に%TYPEを付加して宣言します。 宣言された変数は、テーブルのカラムのデータ型と同じものを宣言したことになります。 テーブル由来の宣言とすることで、テーブルのカラム型の桁数を変えた時にはソース上の変更なしに再度実行で反映されます。

カーソル宣言はテーブルから順次レコードを取得する場合に使用されるものですが、後に詳しく説明します。
尚、USER_SOURCE テーブルの定義の表示を合わせて行っています。

SQL> DECLARE
  2      -- 変数宣言
  3      -- VARCHAR2型宣言
  4      wk_vc1  VARCHAR2(32);
  5      wk_vc2  VARCHAR2(32) := '111111';
  6
  7      -- NUMBER型宣言
  8      wk_nm1  NUMBER;
  9      wk_nm2  NUMBER(9);
 10      wk_nm3  NUMBER(9, 3);   -- 小数点以下3桁で全部で9桁
 11
 12      -- DATE型宣言
 13      wk_dt1  DATE;
 14
 15      -- %TYPEを使った宣言(ユーザ関数が登録されているテーブル:USER_SOURCE から)
 16      wk_type1 USER_SOURCE.NAME%TYPE;     -- NUMBER の宣言と同様
 17      wk_type2 USER_SOURCE.LINE%TYPE;     -- VARCHAR2(4000) の宣言と同様
 18
 19      -- カーソル宣言(テーブル:USER_SOURCE から)
 20      CURSOR wk_cur1 IS
 21          SELECT LINE, TEXT
 22          FROM USER_SOURCE;
 23
 24  BEGIN
 25      -- 何もしない命令
 26      NULL;
 27  END;
 28  /

PL/SQLプロシージャが正常に完了しました。

SQL>
SQL> DESC USER_SOURCE
 名前                                      NULL?    型
 ----------------------------------------- -------- ----------------------------
 NAME                                               VARCHAR2(30)
 TYPE                                               VARCHAR2(12)
 LINE                                               NUMBER
 TEXT                                               VARCHAR2(4000)

変数への代入(値設定)

SQL> DECLARE
  2      -- VARCHAR2型宣言
  3      wk_vc1  VARCHAR2(32);
  4      wk_vc2  VARCHAR2(32) := '111111';
  5      -- NUMBER型宣言
  6      wk_nm1  NUMBER;
  7      wk_nm2  NUMBER(9);
  8  BEGIN
  9      -- 変数へのリテラルの代入
 10      wk_vc1 := 'abcdefg';
 11      wk_nm1 := 1000;
 12      DBMS_OUTPUT.PUT_LINE('wk_vc1=' || wk_vc1);
 13      DBMS_OUTPUT.PUT_LINE('wk_nm1=' || TO_CHAR(wk_nm1));
 14      -- 変数から変数への代入
 15      wk_vc2 := wk_vc1;
 16      wk_nm2 := wk_nm1;
 17      DBMS_OUTPUT.PUT_LINE('wk_vc2=' || wk_vc2);
 18      DBMS_OUTPUT.PUT_LINE('wk_nm2=' || TO_CHAR(wk_nm2));
 19      -- SELECT文による変数への代入
 20      SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD'), TO_CHAR(SYSDATE, 'HH24:MI:SS')
 21          INTO wk_vc1, wk_vc2 FROM DUAL;
 22      DBMS_OUTPUT.PUT_LINE('DATE=' || wk_vc1);
 23      DBMS_OUTPUT.PUT_LINE('TIME=' || wk_vc2);
 24  END;
 25  /
wk_vc1=abcdefg
wk_nm1=1000
wk_vc2=abcdefg
wk_nm2=1000
DATE=2018/12/13
TIME=18:51:48

PL/SQLプロシージャが正常に完了しました。

SQL>

プログラム実行制御(IF文、CASE文、GOTO文)

プログラムの実行を制御する文として IF文、CASE文、GOTO文等があります。 変数の値により条件を判断し処理の振り分けを行います。先ずは IF文 の構造ですが、以下の様になります。 他のプログラム言語と大差は無いと思います。
但し普通の言語だと ELSEIF となるところが ELSIF「E」が抜けていのと、 最後の END IFENDIF の間の空白には注意が必要です。

IF文、CASE文の書式

-- IF文の書式について
IF <条件式1> THEN 
    <処理文1>;
[ELSIF <条件式2> THEN
    <処理文2>;]
...
[ELSIF <条件式n> THEN
    <処理文n>;]
[ELSE
    <処理文>;]
END IF;

-- CASE文の書式について
CASE 
WHEN <判定値1> THEN
    <処理文1>;
[WHEN <判定値2> THEN
    <処理文2>;]
...
[WHEN <判定値n> THEN
    <処理文n>;]
ELSE            -- ELSE文は必須!!
    <処理文>;
END CASE;

-- CASE文の書式についてその2(検索CASE文)
CASE
WHEN <判定式1> THEN
    <処理文1>;
[WHEN <判定式2> THEN
    <処理文2>;]
...
[WHEN <判定式n> THEN
    <処理文n>;]
ELSE
    <処理文>;
END CASE;

以下に IFCASE文 検索CASE文 の例を示します。

IFCASE文 検索CASE文 の例

SQL> DECLARE
  2      -- VARCHAR2型宣言
  3      wk_vc1  VARCHAR2(32);
  4  BEGIN
  5      -- 仮に変数へのリテラルの代入
  6      wk_vc1 := 'a';
  7
  8      -- IF文
  9      IF wk_vc1 = 'a' THEN
 10          DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a" です。');
 11      ELSIF wk_vc1 = 'b' THEN
 12          DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "b" です。');
 13      ELSIF wk_vc1 = 'c' THEN
 14          DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "c" です。');
 15      ELSE
 16          DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a","b","c" 以外です。');
 17      END IF;
 18
 19      wk_vc1 := 'b';
 20      -- CASE文
 21      CASE wk_vc1
 22          WHEN 'a' THEN
 23              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a" です。');
 24          WHEN 'b' THEN
 25              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "b" です。');
 26          WHEN 'c' THEN
 27              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "c" です。');
 28          ELSE
 29              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a","b","c" 以外です。');
 30      END CASE;
 31
 32      wk_vc1 := 'abc';
 33      -- 検索CASE文
 34      CASE
 35          WHEN wk_vc1 = 'a' THEN
 36              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a" です。');
 37          WHEN wk_vc1 = 'b' THEN
 38              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "b" です。');
 39          WHEN wk_vc1 = 'c' THEN
 40              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "c" です。');
 41          ELSE
 42              DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a","b","c" 以外です。');
 43      END CASE;
 44  END;
 45  /
wk_vc1の値は "a" です。
wk_vc1の値は "b" です。
wk_vc1の値は "a","b","c" 以外です。

PL/SQLプロシージャが正常に完了しました。

SQL>

以下に GOTO文 の例を示しますが、余り使用頻度は高くないと思います。
GOTO文でどの位置でもジャンプできるのですが、使い道としては多重ループからの抜出し等でしょうか。 なるべく IFCASE文 で処理するべきと思います。

GOTO文 の例

SQL> DECLARE
  2      -- VARCHAR2型宣言
  3      wk_vc1  VARCHAR2(32);
  4  BEGIN
  5      -- 仮に変数へのリテラルの代入
  6      wk_vc1 := 'a';
  7
  8      -- IF文
  9      IF wk_vc1 = 'a' THEN
 10          GOTO jump_a;
 11      ELSIF wk_vc1 = 'b' THEN
 12          GOTO jump_b;
 13      ELSIF wk_vc1 = 'c' THEN
 14          GOTO jump_c;
 15      END IF;
 16
 17      GOTO jump_end;
 18
 19      <<jump_a>>
 20      DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "a" です。');
 21      GOTO jump_end;
 22
 23      <<jump_b>>
 24      DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "b" です。');
 25      GOTO jump_end;
 26
 27      <<jump_c>>
 28      DBMS_OUTPUT.PUT_LINE('wk_vc1の値は "c" です。');
 29      -- GOTO jump_end;
 30
 31      <<jump_end>>
 32      DBMS_OUTPUT.PUT_LINE('プロシージャが終了しました。');
 33  END;
 34  /
wk_vc1の値は "a" です。
プロシージャが終了しました。

PL/SQLプロシージャが正常に完了しました。

SQL>

プログラム繰返し制御(LOOP文、WHILE...LOOP文、FOR...LOOP文)

プログラムの繰返し用の制御文として、無限ループ用の LOOP文、繰返しの条件付きループ用の WHILE...LOOP文、 繰返し回数を指定してのループ用の FOR...LOOP文があります。
以下にそれぞれの書式を記します。

LOOP文、WHILE...LOOP文、FOR...LOOP文の書式

-- LOOP文の書式について
LOOP
    <処理文>;
    -- ループを抜出す場合
    [ IF <条件式> THEN
        EXIT;
      END IF; ]
    -- ループを抜出す場合その2
    [ EXIT WHEN <条件式>; ]
END LOOP;

-- WHILE...LOOP文の書式について
WHILE <条件式> LOOP
    <処理文>;
END LOOP;

-- FOR...LOOP文の書式について
FOR <ループカウンタ> IN [ REVERSE ] <初期値>..<終了値> LOOP
    <処理文>;
    -- 以下の処理をスキップする場合
    [ CONTINUE WHEN <条件式>;
      <処理文2>; ]
END LOOP;

無限ループ用の LOOP文の例を以下に記します。
ループカウンタを NUMBER で宣言し、ループ内でループカウンタをカウントアップし、 条件式でカウンタが5を超えた場合にループを抜ける様にしています。 EXIT 命令で END LOOP の下に制御が移ることが分かります。

無限ループ用の LOOP文の例

SQL> DECLARE
  2      -- ループカウンタ
  3      WK_CNT NUMBER(9);
  4  BEGIN
  5      -- カウンタ初期化
  6      WK_CNT := 0;
  7      -- 繰り返し処理
  8      LOOP
  9          -- カウンタ加算
 10          WK_CNT := WK_CNT + 1;
 11          -- カウンタが5を超えた場合はループを抜ける
 12          IF WK_CNT > 5 THEN
 13              EXIT;
 14          END IF;
 15          -- EXIT WHEN WK_CNT > 5; この方法でもOK
 16
 17          -- 繰り返し処理
 18          DBMS_OUTPUT.PUT_LINE('...LOOP(' || TO_CHAR(WK_CNT) || ')回目の処理');
 19      END LOOP;
 20      -- EXITでここにくる
 21      DBMS_OUTPUT.PUT_LINE('...LOOP終了');
 22  END;
 23  /
...LOOP(1)回目の処理
...LOOP(2)回目の処理
...LOOP(3)回目の処理
...LOOP(4)回目の処理
...LOOP(5)回目の処理
...LOOP終了

PL/SQLプロシージャが正常に完了しました。

SQL>

繰返しの条件付きループ用の WHILE...LOOP文の例

SQL> DECLARE
  2      -- ループカウンタ
  3      WK_CNT NUMBER(9);
  4  BEGIN
  5      -- カウンタ初期化
  6      WK_CNT := 0;
  7      -- 繰り返し処理
  8      WHILE WK_CNT < 5 LOOP
  9          -- カウンタ加算
 10          WK_CNT := WK_CNT + 1;
 11          -- 繰り返し処理
 12          DBMS_OUTPUT.PUT_LINE('...LOOP(' || TO_CHAR(WK_CNT) || ')回目の処理');
 13      END LOOP;
 14      DBMS_OUTPUT.PUT_LINE('...LOOP終了');
 15  END;
 16  /
...LOOP(1)回目の処理
...LOOP(2)回目の処理
...LOOP(3)回目の処理
...LOOP(4)回目の処理
...LOOP(5)回目の処理
...LOOP終了

PL/SQLプロシージャが正常に完了しました。

SQL>

繰返し回数を指定してのループ用の FOR...LOOP文の例

SQL> BEGIN
  2      -- 繰り返し処理
  3      FOR I IN 1..5 LOOP
  4          -- スキップ処理(偶数の場合)
  5          CONTINUE WHEN (I MOD 2) = 0;
  6          -- 繰り返し処理
  7          DBMS_OUTPUT.PUT_LINE('...LOOP(' || I || ')回目の処理');
  8      END LOOP;
  9      DBMS_OUTPUT.PUT_LINE('...LOOP終了');
 10  END;
 11  /
...LOOP(1)回目の処理
...LOOP(3)回目の処理
...LOOP(5)回目の処理
...LOOP終了

PL/SQLプロシージャが正常に完了しました。

SQL>

ループカウンタ変数に関して通常の変数とは異なる以下の点があります。

  • ループカウンタ変数を変数宣言部で宣言しなくても良い。宣言した数値変数を使用することはできます。
  • ループ処理内ではループカウンタ変数には値を代入できない。

カーソルについて

PL/SQLの使い方において、テーブルからのデータを基にして各種の処理を行うことが重要な目的と思います。 テーブルからのデータを取得する方法の一つにカーソルがあります。 カーソルの考え方は、データを取得するSELECT文を定義し、そのSELECT文を解釈した後に順次1行(レコード)毎のデータを 取得し、最後の行までを取得した時点で処理を終えるというものです。
カーソルの処理の一連の命令を含んだ書式を以下に記します。

カーソルの処理の書式

DECLARE
    -- カーソル定義
    CURSOR <カーソル名> IS <問い合わせ文(SELECT文)>;
    -- カーソル変数宣言
    <カーソル変数名> <カーソル名>%ROWTYPE;
BEGIN
    -- カーソルオープン
    OPEN <カーソル名>;
    -- カーソル処理のループ
    LOOP
        -- 1行のデータの取得
        FETCH <カーソル名> INTO <カーソル変数名>;
        -- カーソルのデータが無くなった??
        IF <カーソル名>%NOTFOUND THEN
            EXIT;
        END IF;
        -- 何かのデータ処理

    END LOOP;
    -- カーソルクローズ
    CLOSE <カーソル名>;
END;

実際にこの書式に従ってプログラムした例を以下に記します。

カーソル処理の例

SQL> DECLARE
  2      -- カーソル定義
  3      CURSOR CUR_TEST IS SELECT ID, NAME FROM TEST ORDER BY ID;
  4      -- カーソル変数宣言
  5      CUR_WK CUR_TEST%ROWTYPE;
  6  BEGIN
  7      -- カーソルオープン
  8      OPEN CUR_TEST;
  9      -- カーソル処理のループ
 10      LOOP
 11          -- 1行のデータの取得
 12          FETCH CUR_TEST INTO CUR_WK;
 13          -- カーソルのデータが無くなった??
 14          IF CUR_TEST%NOTFOUND THEN
 15              EXIT;
 16          END IF;
 17          -- 何かのデータ処理
 18          DBMS_OUTPUT.PUT_LINE('ID:' || CUR_WK.ID || ' NAME:' || CUR_WK.NAME);
 19
 20      END LOOP;
 21      -- カーソルクローズ
 22      CLOSE CUR_TEST;
 23  END;
 24  /
ID:1 NAME:aaa*****
ID:2 NAME:bbb@@@@@
ID:3 NAME:ccc+++++
ID:4 NAME:ddd-----
ID:9 NAME:

PL/SQLプロシージャが正常に完了しました。

SQL>

以下の様に FOR 文を使って処理することもできます。
この方法では、上記の様に自分自身でカーソルをオープンしフェッチ、及びクローズ処理が必要無くなりますので、 簡単な処理の場合にはこちらの方が便利だと思います。

FOR 文を使ったカーソル処理の例

SQL> DECLARE
  2      -- カーソル定義
  3      CURSOR CUR_TEST IS SELECT ID, NAME FROM TEST ORDER BY ID;
  4  BEGIN
  5      -- カーソル処理のループ
  6      FOR CUR_WK IN CUR_TEST LOOP
  7          -- 何かのデータ処理
  8          DBMS_OUTPUT.PUT_LINE('ID:' || CUR_WK.ID || ' NAME:' || CUR_WK.NAME);
  9      END LOOP;
 10  END;
 11  /
ID:1 NAME:aaa*****
ID:2 NAME:bbb@@@@@
ID:3 NAME:ccc+++++
ID:4 NAME:ddd-----
ID:9 NAME:

PL/SQLプロシージャが正常に完了しました。

SQL>

例外処理について(EXCEPTION)

PL/SQLのプログラムの重要な項目として例外処理があります。 プログラムの BEGIN ... END ブロックの中で発生した例外(プログラム実行が不可能な事由)に対応させるための処理です。 そのブロックの中に EXCEPTION 文を宣言し、各例外の種類に対応して例外の処理を記述します。 例外処理の一連の命令を含んだ書式を以下に記します。

例外処理の書式

BEGIN
    <プログラム実行実体>;
    ...
EXCEPTION
    WHEN <例外名1> THEN
        <例外処理1>
    WHEN <例外名2> THEN
        <例外処理2>
    WHEN <例外名n> THEN
        <例外処理n>
END;

-- BEGIN ... END ブロックをネストした場合
BEGIN
    <処理a>;
    BEGIN
        <処理>;
    EXCEPTION
        WHEN <例外名> THEN
            <例外処理>
    END;
    <処理b>;
    ...
    BEGIN
        <処理>;
    EXCEPTION
        WHEN <例外名> THEN
            <例外処理>
    END;
    ...

EXCEPTION
    WHEN <例外名> THEN
        <例外処理>
    ...
END;

例外名はOracleのサイトからの引用ですが、以下のものがあります。尚、表の中で例外名が太字のものがよく使います。

例外名 エラーコード 備考
ACCESS_INTO_NULL -6530 初期化されていないオブジェクトの属性に値を割り当てようとしました。
CASE_NOT_FOUND -6592 CASE文のWHEN句で何も選択されておらず、ELSE句もありません。
COLLECTION_IS_NULL -6531 EXISTS以外のコレクション・メソッドを初期化されていないネストした表やVARRAYに適用しようとしたか、または初期化されていないネストした表やVARRAYの要素に値を割り当てようとしました。
CURSOR_ALREADY_OPEN -6511 すでにオープンされているカーソルをオープンしようとしました。
DUP_VAL_ON_INDEX -1 一意索引によって制約されている列に重複値を挿入しようとしました。
INVALID_CURSOR -1001 無効なカーソル操作です。
INVALID_NUMBER -1722 文字列から数値への変換に失敗しました。
LOGIN_DENIED -1017 ログインの失敗(拒否)
NO_DATA_FOUND +100 単一行のSELECTによって行が戻されなかったか、またはプログラムによって、ネストした表内の削除された要素や連想配列(索引付き表)内の初期化されていない要素が参照されました。
NO_DATA_NEEDED -6548
NOT_LOGGED_ON -1012 データベースに接続せずにデータベース・コールが発行されました。
PROGRAM_ERROR -6501 PL/SQLに内部的な問題が発生しました。
ROWTYPE_MISMATCH -6504 代入文のホスト・カーソル変数とPL/SQLカーソル変数の戻り型に互換性がありません。
SELF_IS_NULL -30625 MEMBERメソッドを起動しようとしましたが、オブジェクトのインスタンスが初期化されていませんでした。
STORAGE_ERROR -6500 PL/SQLのメモリーが不足しているか、メモリーが破損しています。
SUBSCRIPT_BEYOND_COUNT -6533 コレクション内の要素の数より大きい索引番号を使用して、ネストした表またはVARRAYを参照しました。
SUBSCRIPT_OUTSIDE_LIMIT -6532 有効範囲外の索引番号(たとえば-1)を使用して、ネストした表またはVARRAYを参照しました。
SYS_INVALID_ROWID -1410 文字列が値ROWIDを表していないため、ユニバーサルROWIDへの文字列の変換に失敗しました。
TIMEOUT_ON_RESOURCE -51 データベースでリソースを待機している間に、タイムアウトが発生しました。
TOO_MANY_ROWS -1422 単一行のSELECTによって、2つ以上の行が戻されました。
VALUE_ERROR -6502 算術、変換、切捨てまたはサイズ制限のエラーが発生しました。
ZERO_DIVIDE -1476 数値を0(ゼロ)で割ろうとしました。
OTHERS EXCEPTIONで指定した例外名以外のものを全てを表す。

簡単な例として、 ZERO_DIVIDE を使ったものを以下に示します。 この例に特に利用価値があるわけではありませんが、 EXCEPTION の使い方を見て下さい。

例外処理の例(ZERO_DIVIDE)

SQL> DECLARE
  2      -- 数値変数宣言
  3      WK NUMBER(9);
  4  BEGIN
  5      -- 強制的に0で割る
  6      WK := 10 / 0;
  7      DBMS_OUTPUT.PUT_LINE('正常終了');
  8
  9  EXCEPTION
 10      WHEN ZERO_DIVIDE THEN
 11          DBMS_OUTPUT.PUT_LINE('ZERO_DIVIDEエラーが発生!!');
 12      WHEN OTHERS THEN
 13          DBMS_OUTPUT.PUT_LINE('その他のエラーが発生!!');
 14  END;
 15  /
ZERO_DIVIDEエラーが発生!!

PL/SQLプロシージャが正常に完了しました。

SQL>

以下に NO_DATA_FOUND を使った例を示します。 FOR ループの中に BEGIN...END; がありますが、その中に例外処理を宣言しています。 TEST テーブルにはIDが 1 から 4 までしかないのでIDが 5 のSELECT文の実行時に例外が発生します。 EXCEPTION の中で NO_DATA_FOUND の場合の処理と、その他の例外である OTHERS の処理を行っています。

例外処理の例2(NO_DATA_FOUND)

SQL> DECLARE
  2      /* ワーク変数の宣言 */
  3      WK  VARCHAR2(64);
  4  BEGIN
  5      -- 繰り返し処理
  6      FOR I IN 1..5 LOOP
  7          BEGIN
  8              -- TESTテーブルからの取得
  9              SELECT NAME INTO WK FROM TEST WHERE ID = I;
 10              DBMS_OUTPUT.PUT_LINE('ID:' || I || ' NAME=' || WK);
 11          EXCEPTION
 12              -- エラーの場合
 13              WHEN NO_DATA_FOUND THEN
 14                  DBMS_OUTPUT.PUT_LINE('ID:' || I || ' NO_DATA_FOUND のエラーが発生!!');
 15              WHEN OTHERS THEN
 16                  DBMS_OUTPUT.PUT_LINE('ID:' || I || ' その他のエラーが発生!!');
 17          END;
 18      END LOOP;
 19      DBMS_OUTPUT.PUT_LINE('...終了');
 20  END;
 21  /
ID:1 NAME=aaa*****
ID:2 NAME=bbb@@@@@
ID:3 NAME=ccc+++++
ID:4 NAME=ddd-----
ID:5 NO_DATA_FOUND のエラーが発生!!
...終了

PL/SQLプロシージャが正常に完了しました。

SQL>





ページのトップへ戻る