2009-06-03 28 views
7

(甲骨文的PL/SQL)如何確定PL/SQL語句中的行/值拋出錯誤?

如果我有一個拋出一個錯誤一個簡單的SQL語句,即:

DECLARE 
    v_sql_errm varchar2(2048); 
BEGIN 
    UPDATE my_table SET my_column = do_something(my_column) 
     WHERE my_column IS NOT NULL; 
EXCEPTION 
    when others then 
     -- How can I obtain the row/value causing the error (unknown)? 
     v_sql_errm := SQLERRM; 
     insert into log_error (msg) values ('Error updating value (unknown): '|| 
      v_sql_errm); 
END; 

是否有異常塊內的任何方式來確定該行/值該查詢遇到錯誤?我希望能夠記錄它,以便我可以進入並修改/更正導致錯誤的特定數據值。

+1

根據下面的答案,似乎沒有辦法確定導致錯誤的實際行/值。最好的解決方案似乎是使用FOR循環迭代。 – 2009-06-03 16:41:14

+0

相關問題:http://stackoverflow.com/questions/18458012/oracle-jdbc-how-to-know-which-row-throws-unique-key-constraint – Vadzim 2015-02-06 11:18:03

回答

2

使用SAVE EXCEPTIONS子句的解決方案:

SQL> create table my_table (my_column) 
    2 as 
    3 select level from dual connect by level <= 9 
    4/

Table created. 

SQL> create function do_something 
    2 (p_my_column in my_table.my_column%type 
    3 ) return my_table.my_column%type 
    4 is 
    5 begin 
    6 return 10 + p_my_column; 
    7 end; 
    8/

Function created. 

SQL> alter table my_table add check (my_column not in (12,14)) 
    2/

Table altered. 

SQL> declare 
    2 e_forall_error exception; 
    3 pragma exception_init(e_forall_error,-24381) 
    4 ; 
    5 type t_my_columns is table of my_table.my_column%type; 
    6 a_my_columns t_my_columns := t_my_columns() 
    7 ; 
    8 begin 
    9 select my_column 
10   bulk collect into a_my_columns 
11  from my_table 
12 ; 
13 forall i in 1..a_my_columns.count save exceptions 
14  update my_table 
15   set my_column = do_something(a_my_columns(i)) 
16  where my_column = a_my_columns(i) 
17 ; 
18 exception 
19 when e_forall_error then 
20 for i in 1..sql%bulk_exceptions.count 
21 loop 
22  dbms_output.put_line(a_my_columns(sql%bulk_exceptions(i).error_index)); 
23 end loop; 
24 end; 
25/
2 
4 

PL/SQL procedure successfully completed. 

對於非常大的數據集,您可能不想炸燬PGA內存,因此請務必在該情況下使用LIMIT子句。

0

嘗試輸出你的錯誤,看看它是否給你你正在尋找的信息。例如:

EXCEPTION 
    WHEN OTHERS 
    THEN 
     DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END; 
+0

謝謝,但只是給我一個錯誤的描述,例如作爲日期操作的「無效月份」,或者如果值超過列大小,則爲「值太大」。我需要知道哪個值導致了該錯誤,以便我可以對數據進行適當的更正。 – 2009-06-03 14:34:38

0

欲瞭解更多詳細關於執行如何到達這行信息,你可以嘗試顯示這些函數返回的輸出:

  • DBMS_UTILITY.format_error_stack

    格式化當前錯誤堆棧。這可以用於異常處理程序來查看完整的錯誤堆棧。

  • DBMS_UTILITY.format_error_backtrace

    格式從當前的錯誤點到錯誤已經陷入了異常處理程序回溯。如果當前沒有處理錯誤,則返回NULL字符串。

0

嘗試此(未測試):

DECLARE 
     cursor c1 is 
     select key_column, my_column 
     from my_table 
     WHERE my_column IS NOT NULL 
     ORDER BY key_column; 

     my_table_rec my_table%ROWTYPE; 

    BEGIN 

     FOR my_table_rec in c1 
     LOOP 
     UPDATE my_table SET my_column = do_something(my_column) 
      WHERE key_column = my_table_rec.key_column; 
     END LOOP; 

    EXCEPTION 
     when others then 
     insert into log_error (msg) values ('Error updating key_column: ' || my_table_rec.key_column || ', my_column: ' || my_table_rec.my_column); 
    END; 
+0

-1,用於建議從單個更新語句逐行(也稱爲逐慢)處理。 – 2009-06-03 14:49:53

+0

OK Rob!你必須記住,「你不能吃你的蛋糕,並擁有它」。我的解決方案可行你呢? – Christian 2009-06-03 14:59:11

0

PL/SQL定義2個全局變量指錯誤:

SQLERRM:SQL錯誤消息

SQLERRNO: SQL錯誤編號

這在EXCE中是可讀的PTION塊在PL/SQL中。

DECLARE 
    x number; 
BEGIN 
    SELECT 5/0 INTO x FROM DUAL; 
EXCEPTION 
    WHEN OTHERS THEN: 
     dbms_output.put_line('Error Message: '||SQLERRM); 
     dbms_output.put_line('Error Number: '||SQLERRNO); 
END; 
3

如果您使用的是10gR2或更高版本,則可以使用DML錯誤日誌記錄完成此操作。

一個例子:

SQL> create table my_table (my_column) 
    2 as 
    3 select level from dual connect by level <= 9 
    4/

Tabel is aangemaakt. 

SQL> create function do_something 
    2 (p_my_column in my_table.my_column%type 
    3 ) return my_table.my_column%type 
    4 is 
    5 begin 
    6 return 10 + p_my_column; 
    7 end; 
    8/

Functie is aangemaakt. 

SQL> alter table my_table add check (my_column not in (12,14)) 
    2/

Tabel is gewijzigd. 

SQL> exec dbms_errlog.create_error_log('my_table') 

PL/SQL-procedure is geslaagd. 

這將創建一個錯誤記錄表稱爲犯錯$ _my_table。該表是通過添加日誌錯誤子句update語句中填寫:

SQL> begin 
    2 update my_table 
    3  set my_column = do_something(my_column) 
    4  where my_column is not null 
    5   log errors reject limit unlimited 
    6 ; 
    7 end; 
    8/

PL/SQL-procedure is geslaagd. 

SQL> select * from err$_my_table 
    2/

         ORA_ERR_NUMBER$ 
-------------------------------------- 
ORA_ERR_MESG$ 
-------------------------------------------------------------------- 
ORA_ERR_ROWID$ 
-------------------------------------------------------------------- 
OR 
-- 
ORA_ERR_TAG$ 
-------------------------------------------------------------------- 
MY_COLUMN 
-------------------------------------------------------------------- 
            2290 
ORA-02290: check constraint (RWK.SYS_C00110133) violated 
AAGY/aAAQAABevcAAB 
U 

12 

            2290 
ORA-02290: check constraint (RWK.SYS_C00110133) violated 
AAGY/aAAQAABevcAAD 
U 

14 


2 rijen zijn geselecteerd. 

此前10gR2中,你可以使用保存例外條款:http://rwijk.blogspot.com/2007/11/save-exceptions.html