Как Oracle указывает
Добавьте предложение SAVE EXCEPTIONS в ваш оператор FORALL, если вы хотите, чтобы механизм выполнения PL / SQL выполнял все операторы DML, сгенерированные FORALL, даже если один или более чем выйти из строя с ошибкой. Если вы используете ИНДЕКСЫ OF, вам нужно будет немного позаботиться о том, чтобы вернуться к ошибочному утверждению.
Итак, СОХРАНИТЬ ИСКЛЮЧЕНИЯ делает то, что должно делать, поэтому весь FORALL, не поднимая до конца никаких вопросов. Ваша проблема здесь ORA-01438: value larger than specified precision allowed for this column
. Это исключение никогда не проинформирует затронутый столбец. Чтобы зафиксировать проблемный столбец c, у вас есть несколько вариантов.
SQL
В SQL, например, используя sqlplus, вы получите указание того, какой столбец является ответственным, поскольку он отмечен звездочкой, хотя столбец явно не назван в исключении.
SQL> create table t ( c1 number(1) , c2 number(2) , c3 number(3) ) ;
Table created.
SQL> insert into t values ( 1 , 22, 3333 ) ;
insert into t values ( 1 , 22, 3333 )
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
PL / SQL
В PL / SQL исключение обрабатывается модулем EXCEPTION, который управляет SQLCODE и SQLERRM, связанными с ошибкой. В этой ошибке нет никакого указания на столбец:
SQL> declare
2 begin
3 insert into t values ( 1 , 22, 3333 );
4 commit;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at line 3
В этом случае вам может помочь, но отображение значений в случае исключения
SQL> declare
2 v_1 number := 1;
3 v_2 number := 22;
4 v_3 number := 3333;
5 begin
6 insert into t values ( v_1 , v_2, v_3) ;
7 commit;
8 exception when others then
9 dbms_output.put_line( v_1 || '-' || v_2 || '-' || v_3 );
10 raise;
11* end;
SQL> /
1-22-3333
declare
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at line 10
ORA-06512: at line 6
DML ERROR ЖУРНАЛ
DML ERROR LOGGING
- это функция, которая четко вписывается в ваш сценарий. Вы должны применить предложение LOG ERRORS INTO ERROR_TABLE
после создания таблицы ошибок.
Пример
SQL> EXEC DBMS_ERRLOG.CREATE_ERROR_LOG (DML_TABLE_NAME => 'T' , err_log_table_name => 'T_ERRORS' ) ;
PL/SQL procedure successfully completed.
declare
v_1 number := 1;
v_2 number := 22;
v_3 number := 3333;
begin
insert into t values ( v_1 , v_2, v_3) log errors into t_errors;
commit;
exception when others then
raise;
end;
/
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at line 10
ORA-06512: at line 6
SQL> col c1 for a10
SQL> col c2 for a10
SQL> col c3 for a10
SQL> select ORA_ERR_NUMBER$,ORA_ERR_MESG$,c1,c2,c3 from t_errors ;
ORA_ERR_NUMBER$
---------------
ORA_ERR_MESG$
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C1 C2 C3
---------- ---------- ----------
1438
ORA-01438: value larger than specified precision allowed for this column
1 22 3333
В вашем коде c вы должны:
1. Создайте ТАБЛИЦУ ОШИБОК для своей таблицы exception_test с помощью DBMS_ERRLOG.
EXEC DBMS_ERRLOG.CREATE_ERROR_LOG (DML_TABLE_NAME => 'EXCEPTION_TEST' , err_log_table_name => 'T_ERR_EXCEPTION_TEST' );
2. Измените ЗАЯВЛЕНИЕ INSERT, чтобы добавить предложение LOG ERRORS INTO YOUR_ERROR_TABLE
и удалить часть SAVE EXCEPTIONS
. После использования DML_ERROR_LOGGING все исключения будут сохранены в таблице журнала ошибок
FORALL i IN l_tab.first .. l_tab.last
INSERT INTO exception_test
VALUES l_tab(i) log errors into T_ERR_EXCEPTION_TEST;
UPDATE
Вариант для вашего кода
EXE C DBMS_ERRLOG.CREATE_ERROR_LOG (DML_TABLE_NAME => 'EXCEPTION_TEST', err_log_table_name => 'T_ERR_EXCEPTION_TEST');
create or replace procedure BULK_COLLECT_TEST_PROC
as
TYPE t_bulk_collect_test_tab IS TABLE OF bulk_collect_test%ROWTYPE;
l_tab t_bulk_collect_test_tab;
l_error_count NUMBER;
CURSOR c_data IS
SELECT *
FROM bulk_collect_test;
BEGIN
-- first truncate error table
execute immediate ' truncate table T_ERR_EXCEPTION_TEST drop storage ' ;
-- collection and insert
OPEN c_data;
LOOP
FETCH c_data
BULK COLLECT INTO l_tab LIMIT 10000;
EXIT WHEN l_tab.count = 0;
-- Perform a bulk operation.
BEGIN
FORALL i IN l_tab.first .. l_tab.last
INSERT INTO exception_test VALUES l_tab(i) log errors into T_ERR_EXCEPTION_TEST ;
END LOOP;
-- count errors
commit ;
select count(*) into l_error_count from T_ERR_EXCEPTION_TEST;
if l_error_count > 0
then
-- loop over the errors if you want to here by selecting the error
-- table
null;
end if;
EXCEPTION
WHEN OTHERS THEN RAISE;
END;
END LOOP;
END;
/