Регистрация ошибок DML — это особенность Oracle, которая существует уже много лет. Он отлично подходит для регистрации ошибок при большой загрузке без потери всех успешно загруженных строк.
Но вот возможный новый вариант использования для регистрации ошибок DML, даже если вы не выполняете крупномасштабную загрузку. Позвольте мне сначала описать проблему, а затем показать, как логирование ошибок DML может быть решением.
Я создам таблицу с ограничением на столбец:
SQL
xxxxxxxxxx
1
create table t1 (val number not null);
2
-- Table created.
Одна из приятных вещей, появившихся в Oracle (я думаю) еще в версии 8.0, была более подробная информация, когда вы нарушаете эти ограничения. Итак, когда я пытаюсь вставить ноль в эту таблицу.
SQL
xxxxxxxxxx
1
insert into t1 values (null);
2
insert into t1 values (null)
3
-- * ERROR at line 1: ORA-01400: cannot insert NULL into ("SCOTT"."T1"."VAL")
Мне не только говорят, что я получил ORA-1400, мне также говорят столбец (VAL), который вызвал ошибку. Даже если этот INSERT выполняется из процедуры PL / SQL, я все равно получаю эту информацию:
SQL
xxxxxxxxxx
1
exec insert into t1 values (null);
2
BEGIN insert into t1 values (null);
4
END;
5
-- ERROR at line 1: ORA-01400: cannot insert NULL into ("SCOTT"."T1"."VAL")
7
-- ORA-06512: at line 1
Это может показаться не особенно полезным в этом случае, но рассмотрим более верное для жизни приложение, в котором могут быть таблицы с десятками столбцов или даже сотнями столбцов. Знание того, в каком столбце произошла ошибка, - это полезная информация, которую нужно иметь при отладке.
Вам также может понравиться:
Oracle Quick SQL Platform .
Все это кажется просто сладким, пока я не добавлю немного объемного переплета в микс. Вот пакет, который будет массово связывать вставку в таблицу T1.
SQL
x
1
create or replace package bulk_ins as
2
type t1_tt is table of t1%rowtype;
3
procedure bulk_insert;
4
end bulk_ins;
5
-- Package created.
6
create or replace package body bulk_ins as
8
procedure bulk_insert is
9
l_data t1_tt:=t1_tt();
10
begin
11
l_data.extend(2);
12
l_data(1).val:=999;
13
l_data(2).val:=null;
14
begin
16
forall i in 1..l_data.count save exceptions
17
insert into t1 values l_data(i);
18
exception
19
when others then
20
for i in 1..sql%bulk_exceptions.count loop
21
dbms_output.put_line( sqlerrm( -sql%bulk_exceptions(i).error_code ) );
22
end loop;
23
end forall_loop_with_save_except;
24
commit;
25
end bulk_insert;
26
end bulk_ins;
27
-- Package body created.
Даже не запуская код, вы можете видеть в строках 6 и 7, что мы заполняем массив с нулевым значением в одной из записей, поэтому таблица T1 не будет похожа на это после вставки! К счастью, мы будем использовать расширение SAVE EXCEPTIONS, чтобы фиксировать любые ошибки и сообщать о них вызывающей среде. Вот что происходит
SQL
xxxxxxxxxx
1
set serverout on exec bulk_ins.bulk_insert;
2
-- ORA-01400: cannot insert NULL into () PL/SQL procedure successfully completed.
SAVE EXCEPTIONS зафиксировала ошибку, но обратите внимание, что жизненно важное имя столбца было потеряно. Поскольку SAVE EXCEPTIONS фиксирует код ошибки , но когда мы конвертируем его в стандартный текст сообщения об ошибке , точность теряется.
Вот где обработка ошибок DML может помочь и улучшить ситуацию. Я перекодирую тело пакета, чтобы использовать регистрацию ошибок DML и обойдусь без SAVE EXCEPTIONS
SQL
x
1
-- exec DBMS_ERRLOG.create_error_log(dml_table_name=>'T1') PL/SQL procedure successfully completed.
2
create or replace package body bulk_ins as
4
procedure bulk_insert is
5
l_data t1_tt:=t1_tt();
6
begin
7
l_data.extend(2);
8
l_data(1).val:=999;
9
l_data(2).val:=null;
10
forall i in 1..l_data.count
12
insert into t1 values l_data(i) LOG ERRORS REJECT LIMIT UNLIMITED;
13
commit;
15
end bulk_insert;
16
end bulk_ins;
17
-- Package body created.
19
exec bulk_ins.bulk_insert;
21
-- PL/SQL procedure successfully completed.
22
elect * from err$_t1
24
--@pr ============================== ORA_ERR_NUMBER$ : 1400 ORA_ERR_MESG$ : ORA-01400: cannot insert NULL into ("SCOTT"."T1"."VAL") ORA_ERR_ROWID$ : ORA_ERR_OPTYP$ : I ORA_ERR_TAG$ : VAL :
Обратите внимание, что сообщение об ошибке теперь содержит полную информацию, как это было из стандартного оператора вставки SQL. Это круто. Я не говорю, что вы должны спешить и заменить весь ваш код SAVE EXCEPTIONS журналом ошибок DML. Из примера видно, что в управлении этим есть издержки.
Вам необходимо заранее определить таблицу регистрации ошибок, вам нужно будет управлять строками из нескольких сессий, и, очевидно, к каждой загрузке необходимо добавить суффикс запроса к таблице регистрации ошибок, чтобы увидеть, не возникли ли какие-либо ошибки. Но если вам действительно нужно это имя столбца, использование журнала ошибок DML может стать для вас шагом вперед.