DECLARE
宣言部
BEGIN
実行部
EXCEPTION
例外処理部
END;
実行部で例外が発生すると、例外が発生した以降の処理は実行されず、例外処理部に処理が移ります。
例外処理部では、例外を補足する例外ハンドラを定義し、例外に応じた処理を行います。
例外ハンドラは以下のような構文で定義します。
WHEN 例外名 THEN複数の例外に対して同じ処理を行いたい場合は、例外名称をORで繋ぎます。
WHEN 例外名1 OR 例外名2 THEN
まとめると以下のようになります。
DECLARE
BEGIN
例外発生!EXCEPTION部へ処理が遷移
例外発生以降の処理は行われない
EXCEPTION
WHEN 例外名1 THEN
例外1が発生時の処理
WHEN 例外名2 OR 例外名3 THEN
例外2、例外3が発生した時の処理
END;
例外の発生を確認してみます。
以前の記事「PLSQL SQL Developer からテーブル作成 」で作成したテーブルからMemberId=99のMemberNameを取得します。
しかしMemberId=99のデータがないので例外が発生します。
DECLARE
name Member.MemberName%Type;
BEGIN
SELECT MemberName INTO name
FROM Member WHERE MemberId = 99;
SYS.DBMS_OUTPUT.PUT_LINE('MemberId=99のMemberName=' || name);
END;
6行目で「ORA-01403 no data found データが見つかりません。」とエラーが発生します。例外処理を加えてみます。
DECLARE
name Member.MemberName%Type;
BEGIN
SELECT MemberName INTO name
FROM Member WHERE MemberId = 99;
SYS.DBMS_OUTPUT.PUT_LINE('MemberId=99のMemberName=' || name);
EXCEPTION
WHEN no_data_found THEN
SYS.DBMS_OUTPUT.PUT_LINE('例外が発生しました。SQLCODE=' || SQLCODE || '、エラーメッセージ=' || SQLERRM);
END;
今度はエラーが発生せず「例外が発生しました。SQLCODE=100、エラーメッセージ=ORA-01403: データが見つかりません」と表示されます。EXCEPTION部で使用されている
SQLCODEはOracleのエラー番号を返す関数です。
SQLERRMはOracleのエラーメッセージを返す関数です。
WHEN no_data_found THEN はSELECT INTO文でデータが取得できなかった時の例外をキャッチします。
no_data_found以外にも、PLSQLでは最低限必要な例外が事前定義されています。
事前定義されている例外は以下のようなものがあります。
| 例外 | Oracleエラー | SQLCODE値 | 発生原因 |
|---|---|---|---|
| ACCESS_INTO_NULL | 06530 | -6530 | プログラムが未初期化オブジェクトの属性に値を代入しようとしたとき。 |
| CASE_NOT_FOUND | 06592 | -6592 | CASE文のWHEN句で何も選択されておらず、ELSE句もない場合。 |
| COLLECTION_IS_NULL | 06531 | -6531 | プログラムがEXISTS以外のコレクション・メソッドを未初期化のネストした表またはVARRAYに適用しようとしたか、または未初期化のネストした表またはVARRAYの要素に値を代入しようとしたとき。 |
| CURSOR_ALREADY_OPEN | 06511 | -6511 | すでにオープンされているカーソルをオープンしようとしたとき。 カーソルをオープンするには、一度クローズする必要があります。 カーソルFORループは、参照するカーソルを自動的にオープンします。このため、ループの内側ではカーソルをオープンできません。 |
| DUP_VAL_ON_INDEX | 00001 | -1 | UNIQUE索引によって制約されている列に、重複した値を格納しようとしたとき。 |
| INVALID_CURSOR | 01001 | -1001 | オープンされていないカーソルをクローズするなど、不正なカーソル操作を実行しようとしたとき。 |
| INVALID_NUMBER | 01722 | -1722 | SQL文の中で、文字列が正しい数値を表していなかったために、文字列から数値への変換が失敗したとき。 (プロシージャ文では、VALUE_ERRORが呼び出されます。) この例外は、バルクFETCH文のLIMIT句の式が正数に評価されない場合にも呼び出されます。 |
| LOGIN_DENIED | 01017 | -1017 | 不正なユーザー名またはパスワードでデータベースにログオンしようとした場合。 |
| NO_DATA_FOUND | 01403 | +100 | SELECT INTO文が行を戻さなかったとき、ネストした表で削除された要素を参照したとき、または索引付き表で未初期化の要素を参照したとき。この例外は、いくつかのSQLファンクションで終了したことを通知するために内部的に使用されているため、問合せの一部として起動されるファンクション内部で呼び出された場合は、この例外が伝播されても信頼しないでください。 |
| NOT_LOGGED_ON | 01012 | -1012 | データベースに接続していないプログラムが、データベース・コールを発行した場合。 |
| PROGRAM_ERROR | 06501 | -6501 | PL/SQLに内部的な問題が発生した場合。 |
| ROWTYPE_MISMATCH | 06504 | -6504 | 1つの代入の中に含まれるホスト・カーソル変数とPL/SQLカーソル変数の戻り型に互換性がない場合。 オープン・ホスト・カーソル変数をストアド・サブプログラムに渡すとき、実パラメータの戻り型と仮パラメータの戻り型には互換性が必要です。 |
| SELF_IS_NULL | 30625 | -30625 | プログラムがMEMBERメソッドの起動を試行したが、オブジェクト型のインスタンスが初期化されなかった場合。 つまり、組込みパラメータSELFがオブジェクトを指している場合です。このパラメータは、常にMEMBERメソッドに最初に渡されるパラメータです。 |
| STORAGE_ERROR | 06500 | -6500 | PL/SQLのメモリーが足りなくなった場合、またはメモリーが破損された場合。 |
| SUBSCRIPT_BEYOND_COUNT | 06533 | -6533 | コレクション中の要素数より大きい索引番号を使用してネストした表またはVARRAYの要素を参照した場合。 |
| SUBSCRIPT_OUTSIDE_LIMIT | 06532 | -6532 | 有効範囲外(たとえば-1)の索引番号を使用してネストした表またはVARRAYの要素を参照した場合。 |
| SYS_INVALID_ROWID | 01410 | -1410 | 文字列が正しいROWIDを表していなかったために、文字列からユニバーサルROWIDへの変換が失敗した場合。 |
| TIMEOUT_ON_RESOURCE | 00051 | -51 | データベースがリソースを求めて待機しているときにタイムアウトが発生した場合。 |
| TOO_MANY_ROWS | 01422 | -1422 | SELECT INTO文が複数の行を戻した場合。 |
| VALUE_ERROR | 06502 | -6502 | 算術エラー、変換エラー、切捨てエラー、またはサイズ制約エラーが発生した場合。 たとえば、列値を選択し文字変数に代入するときに、その値が変数の宣言された長さよりも長い場合、PL/SQLはその代入を停止してVALUE_ERRORを呼び出します。 プロシージャ文では、文字列から数値への変換が失敗した場合にVALUE_ERRORが呼び出されます。 (SQL文では、INVALID_NUMBERが呼び出されます。) |
| ZERO_DIVIDE | 01476 | -1476 | 数値を0(ゼロ)で割ろうとしたとき。 |
事前に定義されていない例外を補足するには othersハンドラ を使用します。
othersハンドラはすべての例外を補足します。
他の例外をハンドリングしている場合は、一番最後にothersハンドラを書きます。
othersハンドラを他の例外ハンドリングより先に書くとエラーになります。
先ほどのコードを少し修正して、SELECTの結果が複数行返るようにします。
例外はothersハンドラでキャッチされ、エラーメッセージが表示されます。
DECLARE
name Member.MemberName%Type;
BEGIN
SELECT MemberName INTO name
FROM Member;
SYS.DBMS_OUTPUT.PUT_LINE('MemberId=1のMemberName=' || name);
EXCEPTION
WHEN no_data_found THEN
SYS.DBMS_OUTPUT.PUT_LINE('例外が発生しました。SQLCODE=' || SQLCODE || '、エラーメッセージ=' || SQLERRM);
WHEN others THEN
SYS.DBMS_OUTPUT.PUT_LINE('その他の例外が発生しました。SQLCODE=' || SQLCODE || '、エラーメッセージ=' || SQLERRM);
END;
0 件のコメント:
コメントを投稿