PL/SQLの例外処理(前編)超入門「PL/SQL」(8)

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

» 2019年09月11日 05時00分 公開
[小笠原宏幸@IT]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

連載バックナンバー

 本連載は、Oracle Database向けにデータベース言語「SQL(Structured Query Language)」を拡張したプログラミング言語である「PL/SQL(Procedure Language/Structured Query Language)」を理解し、活用するための実践講座です。SQLは知っているけれど、OracleでのPL/SQLは初めてという人向けに、機能の概要と具体的な書き方を解説します。

 PL/SQLで発生したエラーを「例外」と呼びます。今回と次回の2回にわたって、例外が起きたときの対応方法を記述する「例外処理部」について紹介します。今回は、例外処理部がなぜ必要なのかを示した後、例外には3種類あること、さらに「内部例外」の指定方法について解説していきます。

例外処理部の役割

 例外処理部は、PL/SQLで作成したプログラム(PL/SQLブロック)の最後にある「EXCEPTION」から「END」までの部分です。

 例外処理部の役割は、PL/SQLブロックの処理途中で例外が発生した場合、その例外に対応してPL/SQLブロックを正常に終了させることです。まず例外処理部がない場合とある場合の例を順に見ていきましょう。

 以下のサンプルプログラムでは、SELECT INTO文が複数行を戻すため、「ORA-01422エラー」が発生します。例外処理部が存在しないため、ORA-01422エラーに対処できず、PL/SQLブロックが異常終了し、OS側に制御が戻ってしまっています。当然、トランザクションも自動的にロールバックされます。

 そのため、後続の処理が存在する場合でも継続することはできません。

SQL> DECLARE
       e_empno NUMBER;
     BEGIN
       SELECT empno INTO e_empno FROM emp;
     END;
     /
DECLARE
*
行1でエラーが発生しました。:
ORA-01422: 完全フェッチがリクエストよりも多くの行を戻しました
ORA-06512: 行4

 続いて、上記のサンプルプログラムに例外処理部を追加したものを見てみましょう。

 「EXCEPTION」以下に、例外処理部を追加し、ORA-01422エラーが発生した場合はロールバックするように指定しています。なお、ORA-01422エラーには「TOO_MANY_ROWS」という例外名が事前に定義されています。

SQL> DECLARE
       e_empno NUMBER;
     BEGIN
       SELECT empno INTO e_empno FROM emp;
     EXCEPTION
       WHEN too_many_rows THEN rollback;
     END;
     /
PL/SQLプロシージャが正常に完了しました。

 実行部でORA-01422エラーが発生すると制御が例外処理部に移動します。そして、ORA-01422エラーに対して例外処理が行われるとPL/SQLブロックが正常に終了し、トランザクションも継続します。このため、後続の処理が存在する場合でも、問題なく処理を継続できます。

 注意していただきたいのは、例外処理部があったとしても、発生した例外への対処方法が記述されていなければ、PL/SQLブロックが異常終了してしまうという点です。先ほどのサンプルプログラムではORA-01422エラーへの対処方法しか定義されていないため、それ以外の例外が発生した場合は対処できず、PL/SQLブロックが異常終了します。

 最後に、例外処理の有無によるPL/SQLブロックへの影響を整理しておきましょう。

  • 例外処理なし:PL/SQLブロックは異常終了し、トランザクションはロールバックする
  • 例外処理あり:PL/SQLブロックは正常終了し、トランザクションは継続する

例外の種類

 次に例外の種類について解説します。例外には3種類あり、例外発生時の動作や記述方法などが異なります。まずは以下の表にある各例外の特徴を理解しましょう。

種類 概要
内部例外 Oracleが事前に定義した例外(事前定義の内部例外と無名の内部例外の2つに分類)
ユーザー定義例外 ユーザーが独自に定義した例外
定義外例外 PL/SQLブロック内で対処方法が定義されていない例外

 今回は3種類の例外のうち、「内部例外」の特徴や記述方法を解説します。「ユーザー定義例外」と「定義外例外」については、次回(第9回)を参照してください。

内部例外

 内部例外とは、Oracle Databaseの内部で事前に定義されている例外です。Oracle Databaseの規則に反したり、何らかの制限を超えたりした場合に発生します。「ORA-xxxxxの形式でエラー番号が戻されるもの」というとイメージしやすいでしょう。内部例外は、さらに「事前定義の内部例外」と「無名の内部例外」の2つに分類できます。

事前定義の内部例外

 Oracle Databaseによって事前に名前が定義されている内部例外です。冒頭のサンプルプログラムでは、ORA-01422エラーに対して事前定義されている「TOO_MANY_ROWS」例外を使用しています。

 なお、全ての内部例外に名前が定義されているわけではなく、比較的発生しやすい例外のみ定義されています(※1)。代表的な事前定義の内部例外を幾つか紹介しましょう。

※1 Oracle Database 12c R2では、名前が定義されている内部例外が22種類存在する。詳細を「PL/SQL言語リファレンス」マニュアルで確認できる。



例外名 エラー番号 概要
CASE_NOT_FOUND ORA-06592 CASE文のWHEN句やELSE句が指定されていない
NO_DATA_FOUND ORA-01403 SELECT INTO文で1行も戻されない
TOO_MANY_ROWS ORA-01422 SELECT INTO文で複数行が戻された

 まず例外処理部で定義する書式を確認しましょう。

WHEN <例外名> [ OR <例外名> ] THEN 処理文 ; 

 例外処理を行うには例外名の指定が必要ですが、事前定義の内部例外はエラー番号と例外名が事前にひも付けられているため、特別な準備は必要ありません。例外処理部の中でWHEN句に例外名を指定し、THEN句に例外に対する処理内容を記述します。

無名の内部例外

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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