例外処理(エラー処理)(ORACLE編2)


ITコーディネータのシュウです。

1423578385215

娘がディズニーランドに行ってきて、撮ってきた写真です。
昨年、社会現象にもなったアナと雪の女王をテーマにした、スペシャルイベント「アナとエルサのフローズンファンタジー」。入口のところで大きく宣伝してたのを帰る時に撮ったと言ってました。シンデレラ城を舞台にしたプロジェクションマッピング「ワンス・アポン・ア・タイム~スペシャルウィンターエディション」は座席指定券をもらう抽選に当たらなかったので、いい席では見れなかったと残念がってました。

4月からチケットが少し値上がりしてしまうのは残念だけど、それでも何度でも行ってみたくなる魅力がありますよね!

さて、話は変わりますが、dbSheetClientのユーザー事例に紀文食品様が載りました。おでん用の商品などに「紀文」の焼印が押されていることでも有名な、練り製品ではトップシェアを持つ会社ですね。
dbSheetClient
で念願の「品質検査管理システム」を構築したとのこと。詳しくは、こちらを参照してみてください。
http://www.newcom07.jp/dbsheetclient/usrvoice/usrcase8.html

<本日の題材>
例外処理(エラー処理) (Oracle編2)

前回は、ORACLEの例外処理についての一般的記述方法や制御について取り上げてみました。今回は、ORACLEの例外の種類とそれに応じた記述方法について、見てみます。
例外は内部例外とユーザー定義例外にわけられ、内部例外はさらに事前定義の内部例外と無名の内部例外に分けられます。

事前定義の内部例外には、前回の例で示した
・数値データをゼロで割ろうとした「ZERO_DIVIDE」例外(ORA-01476)
・SELECT INTO文で複数の行を戻したときの「TOO_MANY_ROWS」例外(ORA-01422)
・検索の結果1行も戻されない「NO_DATA_FOUND」例外(ORA-01403)
などいろいろあります。

こういったものは、それぞれに名前が定義されているため、例外処理部で個別に処理を指定することができますが、名前が付けられていない無名の内部例外については、宣言部で明示的に名前を付けてあげ、さらに PRAGMA EXCEPTION_INITでORACLEのエラーと例外名を関連付ける必要があります。

例)
DECLARE
  KETA_ERR EXCEPTION;
  PRAGMA EXCEPTION_INIT(KETA_ERR, -01438);
BEGIN
  INSERT INTO DEPT(DEPTNO, DNAME) VALUES(501, '企画部');
  COMMIT;
EXCEPTION
  WHEN KETA_ERR THEN
     DBMS_OUTPUT.PUT_LINE('桁数が大きすぎます');
  WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE(sqlcode);
     DBMS_OUTPUT.PUT_LINE(sqlerrm);
END;
/
plsql_ユーザ定義例外0

これは、DEPT表にデータを登録する際、DEPTNOは2桁の数値でなければならないところ、3桁を登録しようとしたときに出る無名の内部例外、「ORA-01438:この列に許容される指定精度より大きな値です」に名前を付けて、それを例外処理部で使っている例です。

なお、OTHERSハンドラを使用すると、例外処理部で例外名が指定されていないすべての例外を処理することができるため、上記の例では「KETA_ERR」例外以外の例外が発生した場合には、OTHERSハンドラの処理が行われるようになります。
そのときにどのような例外が発生したのかを確認するのに、SQLCODE関数(エラー番号を戻す関数)、SQLERRM関数(エラーメッセージを戻す関数)のようなエラー報告関数をすると便利です。

さて、ユーザー定義例外というのは、ORACLEのエラーではなく、ユーザーが作成する例外になります。

下の例は、FOR LOOP文の繰り返しの中で、ある数量をマイナスしていき、その数値が10未満になった場合には、ユーザー定義例外を呼出して、エラーとして処理するというものです。

例)
DECLARE
  Amount  NUMBER;
  Amount_ERR EXCEPTION;                    -- ユーザー定義例外の宣言
BEGIN
  Amount := 20;
  FOR lc IN 1..30 LOOP
    Amount := Amount – 1;
    IF Amount < 10 THEN
       RAISE Amount_ERR;                     -- ユーザー定義例外の呼出し
    END IF;
  END LOOP;
EXCEPTION
  WHEN Amount_ERR THEN
     DBMS_OUTPUT.PUT_LINE(‘ユーザー定義例外発生: 数量 = ‘||Amount);
END;
/
plsql_ユーザ定義例外1

また、ユーザーが独自に「ORA-xxxx」形式のエラーコードとエラーメッセージを定義して、エラーを表示させるような場合には、RAISE_APPLICATION_ERROR を使用します。
このときにユーザー定義のエラーとして使用が許可されている番号は ORA-20000~ORA-20999 までです。

例)
  RAISE_APPLICATION_ERROR(-20001, 'エラーが発生しました');

また、例外が発生して処理が例外処理部に移ると、制御は実行部には戻らないため、処理の途中でブロックは終了してしまいます。しかし、その後も処理を継続したい場合には、ブロックのネストを使用することで可能になります。

例)
DECLARE
  Amount  NUMBER;
  Amount_ERR EXCEPTION;
BEGIN
  Amount := 20;
  FOR lc IN 1..10 LOOP
    BEGIN                                       -- ブロックのネスト
      Amount := Amount - 2;
      IF Amount = 10 THEN
        RAISE Amount_ERR;
      ELSE
        DBMS_OUTPUT.PUT_LINE('Amount = '||Amount);
      END IF;
    EXCEPTION                                  -- ネストされたブロック内での例外処理
      WHEN Amount_ERR THEN
      DBMS_OUTPUT.PUT_LINE('ユーザー定義例外発生:数量 = '||Amount);
    END;
  END LOOP;
END;
/
plsql_ユーザ定義例外ブロックネスト

上記は、Amountの値が10になった時点で例外が発生していますが、ネストされたブロックの中での例外のため、その後のLOOPの処理が継続されていることが確認できます。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>