[英]Oracle 11gR2 FORALL SAVE EXCEPTIONS on database view not working
我想利用Oracle批量DML操作和異常處理。 我的要求是在數據庫視圖上執行DML操作,在該視圖中它通過視圖觸發器執行一些驗證,然后最終插入/更新基礎表。 但是,Oracle的FORALL .. SAVE EXCEPTIONS似乎沒有捕獲視圖中引發的驗證錯誤。 這是SAVE EXCEPTION的限制/限制,它僅適用於數據庫表而不適用於視圖嗎? Oracle文檔似乎也沒有提到這一點。 以下是我的測試代碼(基於對批量操作中的處理異常的修改):
創建表:
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上的錯誤以進行后檢查。
任何對此的反饋將不勝感激!
立即忘記INSTEAD OF
觸發器。 讓我們專注於BULK EXCEPTIONS
部分。 我的測試用例有一個ID
為NOT NULL
列的表。 一個看法。 我將使用FORALL INSERT
並嘗試通過集合中的索引50和51將NULL
值插入到VIEW
中。 期望在嘗試在VIEW
插入NULL
時獲得EXCEPTION
:
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_APPLICATION_ERROR
並查看。 PL / SQL塊將正常執行。 由於觸發事件而引發的錯誤不是 24381
,因此代碼永遠不會進入異常塊。
您可以嘗試以下類似的方法來捕獲INSTEAD OF TRIGGER中引發的異常嗎?
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.