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

» 2019年09月18日 05時00分 公開
[小笠原宏幸@IT]
前のページへ 1|2       

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

 ここまで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クリエイティブ株式会社)の共著も担当。


前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。