2011-05-16 109 views
62

是否可以创建用户定义的异常并能够更改SQLERRM?Oracle PL/SQL - 通过自定义SQLERRM引发用户定义的异常

例如:

DECLARE 
    ex_custom  EXCEPTION; 
BEGIN 
    RAISE ex_custom; 
EXCEPTION 
    WHEN ex_custom THEN 
     DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END; 
/

的输出为 “用户定义的异常”。有没有可能改变这个讯息?

编辑:这里有一些更多的细节。

我希望这篇文章能说明我想要做的更好。

DECLARE 
    l_table_status  VARCHAR2(8); 
    l_index_status  VARCHAR2(8); 
    l_table_name  VARCHAR2(30) := 'TEST'; 
    l_index_name  VARCHAR2(30) := 'IDX_TEST'; 
    ex_no_metadata  EXCEPTION; 
BEGIN 

    BEGIN 
     SELECT STATUS 
     INTO l_table_status 
     FROM USER_TABLES 
     WHERE TABLE_NAME  = l_table_name; 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
      -- raise exception here with message saying 
      -- "Table metadata does not exist." 
      RAISE ex_no_metadata; 
    END; 

    BEGIN 
     SELECT STATUS 
     INTO l_index_status 
     FROM USER_INDEXES 
     WHERE INDEX_NAME  = l_index_name; 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
      -- raise exception here with message saying 
      -- "Index metadata does not exist." 
      RAISE ex_no_metadata; 
    END; 

EXCEPTION 
    WHEN ex_no_metadata THEN 
     DBMS_OUTPUT.PUT_LINE('Exception will be handled by handle_no_metadata_exception(SQLERRM) procedure here.'); 
     DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END; 
/

实际上,有几十个这样的子块。我想知道是否有一种方法可以为每个子块创建一个用户定义的异常,但是它会给出不同的消息,而不是为每个子块创建单独的用户定义的异常。

在.NET中,这将是有点像有一个自定义异常这样的:

public class ColorException : Exception 
    { 
     public ColorException(string message) 
      : base(message) 
     { 
     } 
    } 

然后,一个方法将有这样的事情:

 if (isRed) 
     { 
      throw new ColorException("Red is not allowed!"); 
     } 

     if (isBlack) 
     { 
      throw new ColorException("Black is not allowed!"); 
     } 

     if (isBlue) 
     { 
      throw new ColorException("Blue is not allowed!"); 
     } 
+0

对不起,如果我不清楚。我会再添加一个例子。 – tgxiii 2011-05-16 16:50:15

回答

117

是的。你只需要使用RAISE_APPLICATION_ERROR函数。如果您还想命名异常,则需要使用EXCEPTION_INIT编译指示,以便将错误编号与指定的异常关联。像

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 ex_custom EXCEPTION; 
    3 PRAGMA EXCEPTION_INIT(ex_custom, -20001); 
    4 begin 
    5 raise_application_error(-20001, 'This is a custom error'); 
    6 exception 
    7 when ex_custom 
    8 then 
    9  dbms_output.put_line(sqlerrm); 
10* end; 
SQL>/
ORA-20001: This is a custom error 

PL/SQL procedure successfully completed. 
+1

正是我需要的!我想我已经在回答我的问题的同时进行了编辑。非常感谢你。 – tgxiii 2011-05-16 17:18:39

29

你可以使用RAISE_APPLICATION_ERROR像这样:

DECLARE 
    ex_custom  EXCEPTION; 
BEGIN 
    RAISE ex_custom; 
EXCEPTION 
    WHEN ex_custom THEN 
     RAISE_APPLICATION_ERROR(-20001,'My exception was raised'); 
END; 
/

这将引发一个异常,如下所示:

ORA-20001: My exception was raised 

错误编号可以是-20001和-20999之间的任何值。

4
declare 
    z exception; 

begin 
    if to_char(sysdate,'day')='sunday' then 
    raise z; 
    end if; 

    exception 
    when z then 
     dbms_output.put_line('to day is sunday'); 
end; 
19

东西,我通常失去跟踪所有我-20001型错误代码,所以我尽量巩固像这样我的所有应用程序错误成为一个不错的包:

SET SERVEROUTPUT ON 

CREATE OR REPLACE PACKAGE errors AS 
    invalid_foo_err EXCEPTION; 
    invalid_foo_num NUMBER := -20123; 
    invalid_foo_msg VARCHAR2(32767) := 'Invalid Foo!'; 
    PRAGMA EXCEPTION_INIT(invalid_foo_err, -20123); -- can't use var >:O 

    illegal_bar_err EXCEPTION; 
    illegal_bar_num NUMBER := -20156; 
    illegal_bar_msg VARCHAR2(32767) := 'Illegal Bar!'; 
    PRAGMA EXCEPTION_INIT(illegal_bar_err, -20156); -- can't use var >:O 

    PROCEDURE raise_err(p_err NUMBER, p_msg VARCHAR2 DEFAULT NULL); 
END; 
/

CREATE OR REPLACE PACKAGE BODY errors AS 
    unknown_err EXCEPTION; 
    unknown_num NUMBER := -20001; 
    unknown_msg VARCHAR2(32767) := 'Unknown Error Specified!'; 

    PROCEDURE raise_err(p_err NUMBER, p_msg VARCHAR2 DEFAULT NULL) AS 
    v_msg VARCHAR2(32767); 
    BEGIN 
    IF p_err = unknown_num THEN 
     v_msg := unknown_msg; 
    ELSIF p_err = invalid_foo_num THEN 
     v_msg := invalid_foo_msg; 
    ELSIF p_err = illegal_bar_num THEN 
     v_msg := illegal_bar_msg; 
    ELSE 
     raise_err(unknown_num, 'USR' || p_err || ': ' || p_msg); 
    END IF; 

    IF p_msg IS NOT NULL THEN 
     v_msg := v_msg || ' - '||p_msg; 
    END IF; 

    RAISE_APPLICATION_ERROR(p_err, v_msg); 
    END; 
END; 
/

然后请致电errors.raise_err(errors.invalid_foo_num, 'optional extra text')使用它,如下所示:

BEGIN 
    BEGIN 
    errors.raise_err(errors.invalid_foo_num, 'Insufficient Foo-age!'); 
    EXCEPTION 
    WHEN errors.invalid_foo_err THEN 
     dbms_output.put_line(SQLERRM); 
    END; 

    BEGIN 
    errors.raise_err(errors.illegal_bar_num, 'Insufficient Bar-age!'); 
    EXCEPTION 
    WHEN errors.illegal_bar_err THEN 
     dbms_output.put_line(SQLERRM); 
    END; 

    BEGIN 
    errors.raise_err(-10000, 'This Doesn''t Exist!!'); 
    EXCEPTION 
    WHEN OTHERS THEN 
     dbms_output.put_line(SQLERRM); 
    END; 
END; 
/

产生此输出:

ORA-20123: Invalid Foo! - Insufficient Foo-age! 
ORA-20156: Illegal Bar! - Insufficient Bar-age! 
ORA-20001: Unknown Error Specified! - USR-10000: This Doesn't Exist!! 
+1

不错的提示!这对我的项目非常有用! – SnakeSheet 2014-07-31 10:49:56

+1

这是一个很好的做法。 [raise_application_error](http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/errors.htm#LNPLS99960)上的两个小问题认为:1)第二个参数的大小限制为2048字节,2 )我希望第三个参数是“true”(而不是默认的“false”)来获得完整的堆栈跟踪。 – user272735 2015-03-05 05:12:28

2
create or replace PROCEDURE PROC_USER_EXP 
AS 
duplicate_exp EXCEPTION; 
PRAGMA EXCEPTION_INIT(duplicate_exp, -20001); 
LVCOUNT NUMBER; 
BEGIN 
    SELECT COUNT(*) INTO LVCOUNT FROM JOBS WHERE JOB_TITLE='President'; 
    IF LVCOUNT >1 THEN 
    raise_application_error(-20001, 'Duplicate president customer excetpion'); 
    END IF; 

    EXCEPTION 
    WHEN duplicate_exp THEN 
    DBMS_OUTPUT.PUT_LINE(sqlerrm); 
END PROC_USER_EXP; 
+0

ORACLE 11g输出将如下所示: - 连接到数据库HR。 ORA-20001:重复总裁客户excelpion 过程退出。 断开数据库HR。 – 2015-12-09 16:24:45