PL/SQLの例外処理(後編):超入門「PL/SQL」(9)(2/2 ページ)
本連載は、「PL/SQL(Procedure Language/Structured Query Language)」を理解し、活用するための実践講座です。前回に引き続き「例外処理」について解説します。
例外処理について考慮しなければならないこと
ここまで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を処理することはありません。
例外処理によって処理が途中で終了してしまうことを防ぐには、例外処理部を含む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ブロックで処理を継続できます。
制御の移動
例外が発生した箇所によって制御の移動先は異なります。
例外の発生箇所 | 移動先 |
---|---|
宣言部、例外処理部 | 例外発生ブロックの外側のブロックにある例外処理部 |
実行部 | 例外発生ブロックの例外処理部 |
これを図で示すと次のようになります。
なお、移動先の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.
関連記事
- DBエンジンを最大限に生かすバッチアプリの作り方
第1回では、バッチアプリケーションを設計するうえで考慮すべき4つのポイントについて解説しました。今回は、Oracleデータベースを最大限に利用したバッチアプリケーションの実装テクニックについて解説します。 - ODTを使ったVisual StudioからのPL/SQL開発
オラクル社が提供する3つの.NET環境用開発ツール「ODP.NET」「ODT」「ODE.NET」。Oracle 10gリリース2に対応した最新版を使って、Oracleデータベースを前提とした.NETアプリケーションの開発手法を解説する。(編集部) - 更新/挿入/削除のSQLを高速化する3つの技とは?
本連載では、Oracleデータベースのパフォーマンス・チューニングの中から、特にSQLのチューニングに注目して、実践レベルの手法を解説する。読者はOracleデータベースのアーキテクチャを理解し、運用管理の実務経験を積んでいることが望ましい。対象とするバージョンは現状で広く使われているOracle9iの機能を基本とするが、Oracle 10gで有効な情報も随時紹介していく。(編集局) - 【Oracle Database】忘れていませんか? 「アラートログ調査」に必要な、たった3つのキホン
データベース管理システムの運用でトラブルが発生したらどうするか。データベースサポートスペシャリストが現場目線の解決Tipsをお届けします。今回は基本編として「アラートログの調査で押さえるべき3つのポイント」を解説します。【Oracle Database 12c対応版】