对于除 ORA-00942 table 之外的所有错误,从 运行 停止存储过程 table 不存在
Stop stored procedure from running for all errors except ORA-00942 table does not exist
我在 Oracle 11g 中有一个存储过程,它将删除某些 table 中特定客户端的记录。下面的脚本是其设置的示例。即使引发异常,它也会继续 运行 每个块。我们希望它在发生除“-942 table 不存在”以外的任何其他异常时停止 运行ning。如果 table 不存在,程序的其余部分应该继续到 运行,所有其他的应该使它停止。我该怎么做?
create or replace PROCEDURE SCHEMA.PURGE_RECORDS
(vCLIENT_ID IN VARCHAR2, pINPUTSCOPE IN VARCHAR2,
pSUCCESS_IND OUT VARCHAR2, pOUTCOME_DESC OUT VARCHAR2)
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME3 T WHERE EXISTS (SELECT 1 FROM TABLE3 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME4 T WHERE EXISTS (SELECT 1 FROM TABLE4 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME5 T WHERE EXISTS (SELECT 1 FROM TABLE5 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
END IF;
END;
您可以显式捕获 ORA-00942 错误,根据需要报告它,然后忽略它;然后要么用 RAISE 处理所有其他异常——这会将异常传播到下一个块,在这种情况下会导致过程终止——或者根本不捕获它们。
ORA-00942 不是 the predefined exceptions so you need to define an exception name and use the PRAGMA EXCEPTION_INIT
clause to associate the exception to the internally defined exception number:
之一
...
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
NO_SUCH_TABLE EXCEPTION;
PRAGMA EXCEPTION_INIT (NO_SUCH_TABLE, -942);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
RAISE;
END;
...
并在每个子块中重复异常捕获。您的 OTHERS
处理程序仍会捕获任何其他异常。捕获和压缩 OTHERS
通常不是一个好主意,最好将其删除并让异常自然传播;即使您正在显示错误(假设运行它的人正在显示输出),您也会丢失原始问题的行号。所以你只需要做:
...
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed, all others will propagate
END;
...
我在 Oracle 11g 中有一个存储过程,它将删除某些 table 中特定客户端的记录。下面的脚本是其设置的示例。即使引发异常,它也会继续 运行 每个块。我们希望它在发生除“-942 table 不存在”以外的任何其他异常时停止 运行ning。如果 table 不存在,程序的其余部分应该继续到 运行,所有其他的应该使它停止。我该怎么做?
create or replace PROCEDURE SCHEMA.PURGE_RECORDS
(vCLIENT_ID IN VARCHAR2, pINPUTSCOPE IN VARCHAR2,
pSUCCESS_IND OUT VARCHAR2, pOUTCOME_DESC OUT VARCHAR2)
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME3 T WHERE EXISTS (SELECT 1 FROM TABLE3 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME4 T WHERE EXISTS (SELECT 1 FROM TABLE4 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME5 T WHERE EXISTS (SELECT 1 FROM TABLE5 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
END IF;
END;
您可以显式捕获 ORA-00942 错误,根据需要报告它,然后忽略它;然后要么用 RAISE 处理所有其他异常——这会将异常传播到下一个块,在这种情况下会导致过程终止——或者根本不捕获它们。
ORA-00942 不是 the predefined exceptions so you need to define an exception name and use the PRAGMA EXCEPTION_INIT
clause to associate the exception to the internally defined exception number:
...
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
NO_SUCH_TABLE EXCEPTION;
PRAGMA EXCEPTION_INIT (NO_SUCH_TABLE, -942);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
RAISE;
END;
...
并在每个子块中重复异常捕获。您的 OTHERS
处理程序仍会捕获任何其他异常。捕获和压缩 OTHERS
通常不是一个好主意,最好将其删除并让异常自然传播;即使您正在显示错误(假设运行它的人正在显示输出),您也会丢失原始问题的行号。所以你只需要做:
...
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed, all others will propagate
END;
...