Oracle 11gR2 for数据库视图上的所有保存异常不工作
我想利用Oracle批量DML操作和异常处理。我的要求是在数据库视图上执行DML操作,通过视图触发器执行一些验证,然后最后插入/更新底层表。然而,甲骨文的福尔。。保存异常似乎无法捕获视图中引发的验证错误。这是否是saveexception的限制/限制,它只处理数据库表而不处理视图?Oracle文档似乎也没有提到这一点。以下是我的测试代码(基于来自的修改): 创建表:Oracle 11gR2 for数据库视图上的所有保存异常不工作,oracle,view,plsql,exception-handling,bulkinsert,Oracle,View,Plsql,Exception Handling,Bulkinsert,我想利用Oracle批量DML操作和异常处理。我的要求是在数据库视图上执行DML操作,通过视图触发器执行一些验证,然后最后插入/更新底层表。然而,甲骨文的福尔。。保存异常似乎无法捕获视图中引发的验证错误。这是否是saveexception的限制/限制,它只处理数据库表而不处理视图?Oracle文档似乎也没有提到这一点。以下是我的测试代码(基于来自的修改): 创建表: create table exception_test ( id number(10) not null ); 在表上创建
create table exception_test (
id number(10) not null
);
在表上创建视图:
create or replace view exception_test_v as
select exception_test.id id
,sysdate daytime
from exception_test;
在视图上创建触发器:
create or replace trigger iud_exception_test
instead of insert or update or delete on exception_test_v
for each row
declare
begin
if inserting then
if nvl(:new.id, 0) = 0 then
RAISE_APPLICATION_ERROR(-20815, 'ID must not be null!');
end if;
insert into exception_test (id) values (:new.id);
end if;
end;
/
数据库视图上DML的测试代码:
declare
TYPE t_tab IS TABLE OF exception_test_v%ROWTYPE;
l_tab t_tab := t_tab();
l_error_count NUMBER;
ex_dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);
BEGIN
-- Fill the collection.
FOR i IN 1 .. 100 LOOP
l_tab.extend;
l_tab(l_tab.last).id := i;
END LOOP;
-- Cause a failure.
l_tab(50).id := NULL;
l_tab(51).id := NULL;
EXECUTE IMMEDIATE 'TRUNCATE TABLE exception_test';
-- Perform a bulk operation.
BEGIN
FORALL i IN l_tab.first .. l_tab.last SAVE EXCEPTIONS
INSERT INTO exception_test_v (id)
VALUES (l_tab(i).id);
EXCEPTION
WHEN ex_dml_errors THEN
l_error_count := SQL%BULK_EXCEPTIONS.count;
DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
FOR i IN 1 .. l_error_count LOOP
DBMS_OUTPUT.put_line('Error: ' || i ||
' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;
END;
视图中索引50上的测试代码错误将触发,而不是处理全部100次插入,并捕获索引50和51上的错误以进行后期检查
对此的任何反馈都将不胜感激 现在就忘掉
而不是触发器。让我们关注批量异常部分。我的测试用例有一个表,其ID
列为notnull
列。对它的看法。我将使用进行所有插入
,并尝试通过集合中的索引50和51将NULL
值插入视图
。当尝试在视图中插入NULL
时,期望得到异常
:
SQL> create table exception_test (
2 ID NUMBER(10) NOT NULL
3 );
Table created.
SQL>
SQL>
SQL> create or replace view exception_test_v as
2 select exception_test.id id
3 ,SYSDATE DAYTIME
4 from exception_test;
View created.
SQL>
SQL> declare
2 TYPE t_tab IS TABLE OF exception_test_v%ROWTYPE;
3
4 l_tab t_tab := t_tab();
5 l_error_count NUMBER;
6
7 ex_dml_errors EXCEPTION;
8 PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);
9 BEGIN
10 -- Fill the collection.
11 FOR i IN 1 .. 100 LOOP
12 l_tab.extend;
13 l_tab(l_tab.last).id := i;
14 END LOOP;
15
16 -- Cause a failure.
17 l_tab(50).id := NULL;
18 l_tab(51).id := NULL;
19
20 EXECUTE IMMEDIATE 'TRUNCATE TABLE exception_test';
21
22 -- Perform a bulk operation.
23 BEGIN
24 FORALL I IN 1 .. L_TAB.COUNT SAVE EXCEPTIONS
25 INSERT INTO exception_test_v (id)
26 VALUES (L_TAB(I).ID);
27 EXCEPTION
28 WHEN EX_DML_ERRORS THEN
29 dbms_output.put_line('Inside exception');
30 l_error_count := SQL%BULK_EXCEPTIONS.count;
31 DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
32 FOR I IN 1 .. L_ERROR_COUNT LOOP
33 DBMS_OUTPUT.put_line('Error: ' || i ||
34 ' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
35 ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
36 END LOOP;
37 END;
38 END;
39 /
Inside exception
Number of failures: 2
Error: 1 Array Index: 50 Message: ORA-01400: cannot insert NULL into ()
Error: 2 Array Index: 51 Message: ORA-01400: cannot insert NULL into ()
PL/SQL procedure successfully completed.
SQL>
SQL> select count(*) from exception_test;
COUNT(*)
----------
98
因此,您可以看到SAVE EXCEPTIONS
中有两个错误
测试用例的问题是,代码永远不会进入EXCEPTION
块。您可以尝试删除RAISE\u APPLICATION\u ERROR
并查看。PL/SQL块将正常执行。由于触发事件而引发的错误是而不是24381
,因此代码永远不会进入异常块。您是否可以尝试以下方法,在其中捕获在中引发的异常而不是触发器
declare
TYPE t_tab IS TABLE OF exception_test_v%ROWTYPE;
l_tab t_tab := t_tab();
l_error_count NUMBER;
ex_dml_errors EXCEPTION;
ex_trigger_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(ex_trigger_errors, -20815);
PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);
BEGIN
-- Fill the collection.
FOR i IN 1 .. 100 LOOP
l_tab.extend;
l_tab(l_tab.last).id := i;
END LOOP;
-- Cause a failure.
l_tab(50).id := NULL;
l_tab(51).id := NULL;
EXECUTE IMMEDIATE 'TRUNCATE TABLE exception_test';
-- Perform a bulk operation.
BEGIN
FORALL i IN l_tab.first .. l_tab.last SAVE EXCEPTIONS
INSERT INTO exception_test_v (id)
VALUES (l_tab(i).id);
EXCEPTION
WHEN ex_dml_errors THEN
l_error_count := SQL%BULK_EXCEPTIONS.count;
DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
FOR i IN 1 .. l_error_count LOOP
DBMS_OUTPUT.put_line('Error: ' || i ||
' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
WHEN ex_trigger_errors THEN
l_error_count := SQL%BULK_EXCEPTIONS.count;
DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
FOR i IN 1 .. l_error_count LOOP
DBMS_OUTPUT.put_line('Error: ' || i ||
' Array Index captured in instead of trigger: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
' Message captured in instead of trigger: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;
END;
您能否在视图中执行单个测试插入并检查是否引发异常???是的,使用上面的我的测试代码,引发的异常是触发器中的ORA-20815
,而不是ORA-24381
中的SAVE EXCEPTIONS
。因此,我无法批量捕获异常,因为FORALL
操作将立即出错。请检查此表的XXX\u updateable\u列(XXX可以是ALL,USER或DBA)以查看ID列是否可更新。从这个答案中可以看出,该列是可更新的,因此不需要触发器,谢谢大家的回复。我需要在这里使用instead of触发器,因为我需要在将数据插入表之前执行一系列验证。我的原始帖子中的raise\u application\u error
只是一个示例,我想测试一下,看看它是否可以捕获到SAVE EXCEPTION
。但似乎SAVE EXCEPTION
实际上只适用于与直接DML操作相关的错误(?)。我试图寻找Oracle文档来确认我的假设,但仍然没有成功。谢谢,我尝试过使用,而其他人则使用,错误在for all INSERT
期间被捕获在索引50上,但是循环只是停在这里,而没有继续执行INSERT的其余部分
,甚至指定了SAVE EXCEPTIONS
。此外,如果未引发异常ex\u dml\u errors-24381
,则使用SAVE EXCEPTIONS
没有意义,因为不再批量处理错误。