検索
連載

PL/SQLの例外処理(後編)超入門「PL/SQL」(9)(2/2 ページ)

本連載は、「PL/SQL(Procedure Language/Structured Query Language)」を理解し、活用するための実践講座です。前回に引き続き「例外処理」について解説します。

Share
Tweet
LINE
Hatena
前のページへ |       

例外処理について考慮しなければならないこと

 ここまで3種類の例外について見てきました。最後に、例外処理に関する考慮事項を3つ解説します。

PL/SQLブロックのネスト

 例外が発生すると制御は例外処理部に移動し、例外処理が終わるとそのPL/SQLブロックは(実行部に戻ることなく)終了します。

 そのため、ある処理の途中で例外が発生した場合、それ以降の処理は実行されません。これを防ぐためには、PL/SQLブロックにネスト(ブロック内にブロックを埋め込むこと)を適用します。

 では、PL/SQLブロックにネストがないサンプルプログラムを見て、何が起こるのか確かめてみましょう。

SQL> DECLARE
       err EXCEPTION;
       CURSOR dept_cur IS SELECT * FROM dept;
     BEGIN
       FOR dept_rec IN dept_cur LOOP
           IF dept_rec.deptno = 30
             THEN RAISE err;
           ELSE null;
           END IF;
         DBMS_OUTPUT.PUT_LINE(dept_rec.deptno);
       END LOOP;
     EXCEPTION
       WHEN err THEN DBMS_OUTPUT.PUT_LINE('値は無効');
     END;
     /
10
20
値は無効
PL/SQLプロシージャが正常に完了しました。

 このプログラムはDEPT表のDEPTNO列の値(10、20、30、40を格納済み)をカーソルFORループによって順番に変数へ代入しています。値が30の場合は例外処理に飛び、その他の値の場合はDBMS_OUT.PUT_LINEで変数の値を画面上に表示します。

 ループ処理の1回目に変数に代入される値は10、2回目は20のため、DBMS_OUT.PUT_LINEにより変数内の値を表示します。

 3回目の値が30のため、IF文内でRAISE文を実行し、例外処理部に移動して例外処理(DBMS_OUT.PUT_LINEにより「値は無効」と表示)を実行します。WHEN句の次行の記述が「END」のため、このままPL/SQLブロックが終了してしまい、値40を処理することはありません。


図1 PL/SQLブロックにネストがない場合の処理の流れ

 例外処理によって処理が途中で終了してしまうことを防ぐには、例外処理部を含むPL/SQLブロックにネストを作ります。では、修正版のサンプルプログラムを見てみましょう。

SQL> DECLARE
       err EXCEPTION;
       CURSOR dept_cur IS SELECT * FROM dept;
     BEGIN
       FOR dept_rec IN dept_cur LOOP
         BEGIN
             IF dept_rec.deptno = 30
               THEN RAISE err;
             ELSE null;
             END IF;
           DBMS_OUTPUT.PUT_LINE(dept_rec.deptno);
         EXCEPTION
           WHEN err THEN DBMS_OUTPUT.PUT_LINE('値は無効');
         END;
       END LOOP;
     END;
     /
10
20
値は無効
40
PL/SQLプロシージャが正常に完了しました。

 修正点は例外処理部を含むPL/SQLブロックにネストを適用して、そのブロックをLOOP文で囲んだことです。このようにすれば、例外処理部で例外に対処した後、外側にあるPL/SQLブロックの「END LOOP」により「LOOP」に戻り、再度ネストを適用したPL/SQLブロックで処理を継続できます。


図2 PL/SQLブロックにネストを適用した場合の処理の流れ

制御の移動

 例外が発生した箇所によって制御の移動先は異なります。

例外の発生箇所 移動先
宣言部、例外処理部 例外発生ブロックの外側のブロックにある例外処理部
実行部 例外発生ブロックの例外処理部

 これを図で示すと次のようになります。


図3 制御の移動の違い

 なお、移動先のPL/SQLブロックで例外を処理できなかった場合、さらに外側のPL/SQLブロックの例外処理部に移動します。このような特徴があるため、定義外例外に対処できるOTHERSハンドラは、一番外側のPL/SQLブロックの例外処理部に記述するようにしましょう。

ユーザー定義のエラーメッセージ

 RAISE_APPLICATION_ERRORを使用すると、RAISE文と同様に例外を発生させ、ユーザーが任意で定義した「ORA-xxxxx」形式のエラーコードとエラーメッセージを戻すことができます。ユーザーが定義した例外を内部例外のように見せたい場合に有効です。書式は次の通りです。

RAISE_APPLICATION_ERROR( <エラー番号> , <エラーメッセージ> ) ;
エラー番号:-20000から-20999の間で任意の番号を定義します
エラーメッセージ:2048バイト以内で任意の文字列を指定します

 続いて、RAISE_APPLICATION_ERRORを使用したサンプルプログラムを見ていきましょう。

SQL> DECLARE
       e_sal NUMBER;
     BEGIN
       SELECT sal INTO e_sal FROM emp WHERE empno = 7369;
         IF e_sal < 1000
           THEN RAISE_APPLICATION_ERROR(-20101,'Value is below specified');
         ELSE null;
         END IF;
     END;
     /
DECLARE
*
行1でエラーが発生しました。:
ORA-20101: Value is below specified
ORA-06512: 行6

 このプログラムでは、実行部のIF文のTHEN句にRAISE_APPLICATION_ERRORを指定しています。

 RAISE_APPLICATION_ERRORを実行すると、指定したエラー番号とメッセージが表示されました。なお、内部的にはPL/SQLブロックが異常終了し、トランザクションがロールバックされます。

 前回と今回の2回にわたって例外処理部を解説しました。例外処理部は、例外が発生してもプログラムを正常に終了させて、処理を継続するために必要です。しっかりと理解しておきましょう。

 今回をもって、宣言部、実行部、例外処理部の各部の解説が終了しました。どの回で触れた内容も、PL/SQLプログラムを作成する上で基本となる機能ばかりです。体系的な理解が必要です。

筆者紹介

小笠原宏幸(おがさわら ひろゆき)

株式会社アシスト データベース技術本部所属。普段はフィールドエンジニアとしての支援作業や、Oracle、PostgreSQL、JP1などの分野で研修講師を担当。また、書籍「SQL逆引き大全363の極意」(株式会社秀和システム)をはじめ、「これならわかるOracle超入門教室」(株式会社翔泳社)、「プロとしてのPL/SQL入門」(SBクリエイティブ株式会社)の共著も担当。


Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る