サーチ…


前書き

Oracleはさまざまな例外を生成します。不明瞭なメッセージでコードを停止させることがいかに面倒なのか、あなたは驚くかもしれません。簡単に修正できるPL / SQLコードの能力を向上させるには、最低レベルで例外を処理する必要があります。カーペットの下の例外を隠すことは絶対にしないでください

定義済みのエラー

例外処理

  1. 例外とは何ですか?

    PL / SQLでの例外は、プログラムの実行中に作成されるエラーです。

    例外には3つのタイプがあります。

    • 内部定義された例外
    • 定義済みの例外
    • ユーザー定義の例外
  1. 例外処理とは何ですか?

    例外処理は、たとえコーディングミス、ハードウェア障害などのランタイムエラーが発生したとしても、プログラムを実行し続ける可能性があります。突然終了することは避けてください。

構文

例外セクションの一般的な構文:

declare
    declaration Section
begin
    some statements

exception
    when exception_one then
        do something
    when exception_two then
        do something
    when exception_three then
        do something
    when others then
        do something
end;

例外セクションは、PL / SQLブロックの最後にある必要があります。 PL / SQLはブロックをネストする機会を与え、各ブロックはそれ自身の例外セクションを持つかもしれません:

create or replace procedure nested_blocks
is
begin
    some statements
    begin
        some statements
        
    exception
        when exception_one then
            do something
    end;
exception 
    when exception_two then
        do something
end;

ネストされたブロックで例外が発生した場合、内部例外セクションで処理する必要がありますが、内部例外セクションがこの例外を処理しない場合、この例外は外部ブロックの例外セクションに移動します。

内部定義された例外

内部的に定義された例外には名前はありませんが、独自のコードがあります。

それをいつ使うのですか?

データベース操作で特定の例外が発生する可能性がある場合は、名前を持たない例外を指定することができます。名前を指定すると、例外ハンドラを記述することができます。そうでない場合は、あなただけでそれらを使用することができothersの例外ハンドラ。

構文

declare 
    my_name_exc exception;
    pragma exception_init(my_name_exc,-37);
begin
    ...
exception 
    when my_name_exc then
        do something
end;

my_name_exc exception;それは例外名の宣言です。

pragma exception_init(my_name_exc,-37);内部的に定義された例外のエラーコードに名前を割り当てます。

私たちは、empテーブルの主キーであるemp_idと、deptテーブルの外部キーを持っています。子レコードがあるときにemp_idを削除しようとすると、コード-2292で例外がスローされます。

create or replace procedure remove_employee
is
    emp_exception exception;
    pragma exception_init(emp_exception,-2292);
begin
    delete from emp where emp_id = 3;
exception
    when emp_exception then
        dbms_output.put_line('You can not do that!');
end;
/

Oracleドキュメントでは、「ユーザー定義の名前を持つ内部的に定義された例外は、依然として内部定義の例外であり、ユーザー定義の例外ではありません。

定義済みの例外

あらかじめ定義された例外は内部的に定義された例外ですが、名前はあります。 Oracleデータベースは、この種の例外を自動的に発生させます。

create or replace procedure insert_emp
is
begin
    insert into emp (emp_id, ename) values ('1','Jon');

exception
    when dup_val_on_index then
        dbms_output.put_line('Duplicate value on index!');
end;
/

以下は、例の例外コードの名前です。

例外名エラーコード
何もデータが見つかりませんでした -1403
ACCESS_INTO_NULL -6530
CASE_NOT_FOUND -6592
ROWTYPE_MISMATCH -6504
TOO_MANY_ROWS -1422
ZERO_DIVIDE -1476

Oracle Webサイトでの例外名とそのコードの完全なリスト。

ユーザー定義の例外

名前が示すように、ユーザー定義の例外はユーザーによって作成されます。独自の例外を作成する場合は、次の操作を行う必要があります。

  1. 例外を宣言する
  2. あなたのプログラムからそれを上げる
  3. 彼を捕まえるのに適した例外ハンドラを作成します。

私は労働者のすべての給与を更新したい。しかし、労働者がいない場合は、例外を提起してください。

create or replace procedure update_salary
is
    no_workers exception;
    v_counter number := 0;
begin
    select count(*) into v_counter from emp;
    if v_counter = 0 then
        raise no_workers;
    else
        update emp set salary = 3000;
    end if;

    exception
        when no_workers then
            raise_application_error(-20991,'We don''t have workers!');                
end;
/

それはどういう意味raise

例外が発生したときに自動的にデータベースサーバーによって例外が発生しますが、必要に応じてraiseを使用して例外を明示的に呼び出すことができます。

プロシージャraise_application_error(error_number,error_message);

  • error_numberは-20000〜-20999の間でなければなりません
  • error_messageエラーが発生したときに表示するメッセージ。

カスタム例外を定義し、それを発生させ、それがどこから来ているかを見てください

これを説明するために、ここでは3つの異なる「間違った」振る舞いを持つ関数があります

  • パラメータは完全に愚かです:ユーザー定義の式を使用します
  • パラメータにはタイプミスがあります:Oracle標準のNO_DATA_FOUNDエラーを使用します
  • 別の、しかし扱われていないケース

あなたの基準に自由に適応してください:

DECLARE
  this_is_not_acceptable EXCEPTION;
  PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077);
  g_err varchar2 (200) := 'to-be-defined';
  w_schema all_tables.OWNER%Type;

  PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2)
  Is 
    w_err varchar2 (200) := 'to-be-defined';
  BEGIN
    w_err := 'get_schema-step-1:';
    If (p_table = 'Delivery-Manager-Is-Silly') Then
      raise this_is_not_acceptable;
    end if;
    w_err := 'get_schema-step-2:';
    Select owner Into p_schema 
      From all_tables
     where table_name like(p_table||'%');
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- handle Oracle-defined exception
     dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.');
  WHEN this_is_not_acceptable THEN
    -- handle your custom error
     dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.');
  When others then
     dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm);
     raise;    
  END Get_schema;  

BEGIN
  g_err := 'Global; first call:';
  get_schema('Delivery-Manager-Is-Silly', w_schema);
  g_err := 'Global; second call:';
  get_schema('AAA', w_schema);
  g_err := 'Global; third call:';
  get_schema('', w_schema);
  g_err := 'Global; 4th call:';
  get_schema('Can''t reach this point due to previous error.', w_schema);
  
EXCEPTION
  When others then
     dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm);
  -- you may raise this again to the caller if error log isn't enough.
--  raise;
END;
/

定期的なデータベースを提供する:

[WARN]get_schema-step-1:Please don't make fun of the delivery manager.
[WARN]get_schema-step-2:This can happen. Check the table name you entered.
[ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
[ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows

まれなケースを処理するための例外がここにあることを忘れないでください私はすべてのアクセスで例外を起こしたアプリケーションを見ただけで、ユーザーのパスワードを要求し、「接続されていません」と言いました。

接続エラー例外の処理

各標準Oracleエラーは、エラー番号と関連付けられています。あなたのコードで何がうまくいかないかを予測することは重要です。ここで別のデータベースに接続するには、次のようにします。

  • -28000アカウントがロックされています
  • -28001パスワードが期限切れです
  • -28002猶予期間
  • -1017間違ったユーザー/パスワード

ここでは、データベースリンクで使用されているユーザに何がうまくいかないかをテストする方法があります:

declare
  v_dummy number;
begin
  -- testing db link
  execute immediate 'select COUNT(1) from dba_users@pass.world' into v_dummy ;
  -- if we get here, exception wasn't raised: display COUNT's result
  dbms_output.put_line(v_dummy||' users on PASS db');

EXCEPTION
  -- exception can be referred by their name in the predefined Oracle's list
    When LOGIN_DENIED 
    then  
        dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN');
    When Others 
    then 
  -- or referred by their number: stored automatically in reserved variable SQLCODE    
        If  SQLCODE = '-2019'
        Then    
          dbms_output.put_line('ORA-2019 / Invalid db_link name');
        Elsif SQLCODE = '-1035'
        Then
          dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA');        
        Elsif SQLCODE = '-28000'
        Then
          dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA');
        Elsif SQLCODE = '-28001'
        Then
          dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE');
        Elsif SQLCODE  = '-28002'
        Then
          dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT');
        Else
   -- and if it's not one of the exception you expected
          dbms_output.put_line('Exception not specifically handled');
          dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM);
        End if;
END;
/


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow