对于除 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;

    ...