确定在pl sql块中导致VALUE_ERROR的数据的目标

时间:2015-03-27 08:41:23

标签: database oracle plsql error-handling

我的软件包正在提出ORA-06502:PL / SQL:数字或值错误。

我可以在catch块中添加一些代码来识别哪些数据未成功插入哪个数据?

现在我只有:

WHEN OTHERS
 ...log SQLCODE and SQLERRM...
 RAISE PROGRAM ERROR;
 RETURN;

谢谢。

2 个答案:

答案 0 :(得分:1)

让我们说你有这样的情况:

CREATE TABLE MY_TABLE (PK NUMBER PRIMARY KEY, COL_A NUMBER(2), COL_B NUMBER(2));

BEGIN
    INSERT INTO MY_TABLE
    SELECT LEVEL AS PK, ROUND(100*DBMS_RANDOM.NORMAL) AS COL_A, ROUND(100*DBMS_RANDOM.NORMAL) AS COL_B
    FROM dual
    CONNECT BY LEVEL < 20;
EXCEPTION
    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE (DBMS_UTILITY.FORMAT_ERROR_STACK);
        DBMS_OUTPUT.PUT_LINE (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;

ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at line 2

显然,您既不知道产生错误的行也不知道列。找到它的一种方法是这一个:

CREATE TABLE MY_TABLE_TEMP AS
SELECT LEVEL AS PK, ROUND(100*DBMS_RANDOM.NORMAL) AS COL_A, ROUND(100*DBMS_RANDOM.NORMAL) AS COL_B
FROM dual
CONNECT BY LEVEL < 20;

DECLARE
sqlstr VARCHAR2(1000);
BEGIN

    FOR aRow IN (SELECT * FROM MY_TABLE_TEMP) LOOP
        INSERT INTO MY_TABLE (PK) VALUES (aRow.PK); 
        FOR aCol IN (SELECT * FROM user_tab_cols WHERE table_name = 'MY_TABLE_TEMP') LOOP
        BEGIN
            sqlstr := 'UPDATE MY_TABLE a SET '||aCol.column_name||' = (SELECT '||aCol.column_name||' FROM MY_TABLE_TEMP b WHERE a.PK = b.PK) WHERE a.PK = :pk';
            EXECUTE IMMEDIATE sqlstr USING aRow.PK;
        EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE ( 'Error at line '||aRow.PK||' for column '||aCol.column_name ||' -> '||SQLERRM);
        END;
        END LOOP;
                DBMS_OUTPUT.PUT_LINE ( 'Line '||aRow.PK||' -> OK');
    END LOOP;

END;

Line 1 -> OK
Line 2 -> OK
Error at line 3 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 3 -> OK
Error at line 4 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Line 4 -> OK
Error at line 5 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Line 5 -> OK
Error at line 6 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Line 6 -> OK
Error at line 7 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 7 -> OK
Error at line 8 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Error at line 8 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 8 -> OK
Error at line 9 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Line 9 -> OK
Error at line 10 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 10 -> OK
Line 11 -> OK
Error at line 12 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 12 -> OK
Line 13 -> OK
Line 14 -> OK
Line 15 -> OK
Line 16 -> OK
Error at line 17 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 17 -> OK
Line 18 -> OK
Error at line 19 for column COL_A -> ORA-01438: value larger than specified precision allowed for this column
Error at line 19 for column COL_B -> ORA-01438: value larger than specified precision allowed for this column
Line 19 -> OK

答案 1 :(得分:0)

多次阅读以下引文,直到您完全理解为止。

  

当其他人几乎总是一个BUG,除非立即跟进   通过RAISE。

  • WHEN OTHERS 隐藏错误的来源。

  • WHEN OTHERS 会破坏程序调用的原子性

请注意,对于错误, RAISE –> CATCH –> HANDLE

因此,首先删除所有异常处理程序,然后重新执行PL / SQL块。错误堆栈将包含正确的行号和其他错误详细信息。

阅读https://lalitkumarb.wordpress.com/2014/05/02/when-others-then-null-a-bug/

例如,

SQL> CREATE OR REPLACE PROCEDURE p_test_others(i_val IN VARCHAR2) AS
2       o_val NUMBER;
3    BEGIN
4       SELECT i_val INTO o_val FROM dual;
5       DBMS_OUTPUT.PUT_LINE(o_val);
6    EXCEPTION
7       WHEN OTHERS THEN
8          DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
9          DBMS_OUTPUT.PUT_LINE('Message: '||SQLERRM);
10         RAISE;
11    END;
12    /
Procedure created

SQL>
SQL> BEGIN
2       p_test_others('a');
3    END;
4    /
SQLCODE: -6502
Message: ORA-06502: PL/SQL: numeric or value error: character to number conversion error
BEGIN
p_test_others('a');
END;
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "P_TEST_OTHERS", line 10
ORA-06512: at line 2

否则,

要记录错误,请使用:

  • dbms_utility.format_error_stack
  • dbms_utility.format_error_backtrace

获取调用堆栈。

例如,

SQL> declare
  2    v1 integer := 1;
  3    v2 integer := 0;
  4    v3 integer;
  5    procedure p1 (v1 in integer, v2 in integer, v3 out integer) is 
  6    begin 
  7      v3 := v1 / v2;
  8    end;
  9    procedure p2 (v1 in integer, v2 in integer, v3 out integer) is 
 10    begin 
 11      p1 (v1, v2, v3);
 12    end;
 13  begin
 14    p2 (v1, v2, v3);
 15  exception
 16    when others then
 17      dbms_output.put_line ('---------------------');
 18      dbms_output.put_line ('This is what you record in log table:');
 19      dbms_output.put (dbms_utility.format_error_stack);
 20      dbms_output.put (dbms_utility.format_error_backtrace);
 21      dbms_output.put_line ('---------------------');
 22      raise;
 23  end;
 24  /
---------------------
This is what you record in log table:
ORA-01476: divisor is equal to zero
ORA-06512: at line 7
ORA-06512: at line 11
ORA-06512: at line 14
---------------------
declare
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at line 22

更新每个OP的请求

带有异常块的

,行号将转到异常处理程序的行号。

SQL> BEGIN
  2    INSERT INTO t
  3      (A
  4      ) VALUES
  5      ('one'
  6      );
  7  EXCEPTION
  8  WHEN OTHERS THEN
  9    RAISE;
 10  END;
 11  /
BEGIN
*
ERROR at line 1:
ORA-12899: value too large for column "LALIT"."T"."A" (actual: 3, maximum: 1)
ORA-06512: at line 9


SQL>

没有异常阻止,您可以使用错误来源的正确行号:

SQL> BEGIN
  2    INSERT INTO t
  3      (A
  4      ) VALUES
  5      ('one'
  6      );
  7  END;
  8  /
BEGIN
*
ERROR at line 1:
ORA-12899: value too large for column "LALIT"."T"."A" (actual: 3, maximum: 1)
ORA-06512: at line 2


SQL>

因此,错误堆栈会告诉您schametable_namecolumn_name以及其他详细信息,例如允许的最大尺寸和实际尺寸。

对于更具体或自定义的错误记录,请使用异常块中的所有必需列名编写您自己的代码,以便在这些列中插入值时记录错误。