2009-06-03 9 views
7

(Oracle PL/SQL)Jak określić błąd rzucania wiersz/wartość w instrukcji PL/SQL?

Jeśli mam prostą instrukcję SQL, która rzuca błąd, a mianowicie:

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; 

Czy jest jakiś sposób w bloku wyjątków określić wiersz/wartość, na której zapytanie napotyka błąd? Chciałbym móc go zarejestrować, aby następnie mógł wejść i zmodyfikować/poprawić konkretną wartość danych powodującą błąd.

+1

Na podstawie poniższych odpowiedzi nie wydaje się, aby można było określić faktyczny wiersz/wartość powodującą błąd. Najlepszym rozwiązaniem wydaje się być iteracja za pomocą pętli FOR. –

+0

Powiązane pytanie: http://stackoverflow.com/questions/18458012/oracle-jdbc-how-to-know-which-row-throws-unique-key-constraint – Vadzim

Odpowiedz

2

Roztwór używając ZAPISZ EXCEPTIONS klauzuli:

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. 

Dla bardzo dużych zestawów danych prawdopodobnie nie chcesz wysadzić pamięci PGA, więc koniecznie użyj klauzuli LIMIT w tym przypadku.

0

spróbuj wydrukować swój błąd i sprawdź, czy zawiera informacje, których szukasz. Na przykład:

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

Dzięki, ale to tylko daje mi opis błędu takiego jako "nieprawidłowy miesiąc" dla operacji daty lub "wartość za duża", jeśli wartość przekracza rozmiar kolumny. Muszę wiedzieć, która wartość spowodowała ten błąd, aby móc wprowadzić odpowiednie korekty danych. –

0

Dla bardziej szczegółowo informacje dotyczące sposobu wykonania przybył na danej linii, można spróbować wyświetlania wyjścia zwracane przez te funkcje:

  • DBMS_UTILITY.format_error_stack:

    Sformatuj bieżący stos błędów. To może być użyte w procedurach obsługi wyjątków, aby spojrzeć na pełny stos błędów.

  • DBMS_UTILITY.format_error_backtrace:

    Formatowanie backtrace z punktu bieżącego błędu do obsługi wyjątków w którym błąd został złapany. Ciąg NULL jest zwracany, jeśli obecnie nie jest obsługiwany żaden błąd.

0

Spróbuj tego (nie testowane):

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 za sugerowanie przejścia z pojedynczej instrukcji aktualizowania do przetwarzania wiersz po rzędzie (zwanego również spowolnianiem). –

+0

OK Rob! Musisz mieć na uwadze, że "nie możesz zjeść swojego ciasta i mieć go również". Moje rozwiązanie działa. Co z twoim? – Christian

+0

Tak, myślałem o iteracji przez nich indywidualnie i otrzymaniu tego w ten sposób ... jest to ogromny zbiór danych i miał nadzieję uzyskać odpowiedź bezpośrednio, bez konieczności iteracji (i nauczyć się czegoś nowego w tym samym czasie!). Jest to dobra sugestia, dzięki! –

0

PL/SQL definiuje 2 zmienne globalne do odnoszą się do błędów:

SQLERRM: SQL error Wiadomość

SQLERRNO: Błąd SQL Numer

Można go odczytać w pliku EXCE Blok PTION w twoim 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; 
+0

To daje mi błąd, a nie wartość powodującą błąd. –

3

Można to zrobić za pomocą rejestrowania błędów DML, jeśli korzystasz z wersji 10gR2 lub nowszej.

Przykład:

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. 

Stwarza tabela rejestrowanie błędów nazywa błądzić $ _my_table.Tabela ta jest wypełniona przez dodanie klauzuli dziennika błędów do wyciągu zmiana:

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. 

Przed 10gR2, można użyć ZAPISZ EXCEPTIONS klauzuli: http://rwijk.blogspot.com/2007/11/save-exceptions.html

+0

Przeczytałem to, a także link do twojego bloga i chyba nie rozumiem tego nadal tylko daje mi komunikaty o błędach (tj. SQLCODE i SQLERRM), a nie wartość danych powodująca błąd. To niestety nie jest pomocne. BTW utknąłem przy użyciu 9g. –

+0

Jeśli przyjrzysz się zawartości err $ _my_table, zauważysz, że moja_kolumna mówi 12 i 14, które są nowymi wartościami, których nie udało się zaktualizować. Opublikuję kolejną odpowiedź, specjalnie dla twojej wersji 9i. Także dlatego, że boli mnie to, że wybrałeś podejście rząd po rzędzie :-) –

Powiązane problemy