您的數據模型是一個問題,因爲它應該按照Rene的建議進行標準化。但是,考慮到你不能那樣做,並且因爲你的問題的一部分已經是一個變異的表錯誤(來自評論)。 和假設您使用的是11g或更高版本,則可以使用複合觸發器解決這兩個問題。
這是避免變異表錯誤的方法之一,因爲它允許您維護在行級構建的受影響行的列表,然後在語句級使用該集合。
這個想法只是修改了一點也保持跟蹤你是否擊中觸發第二次在你的語句級觸發器,你可以用它來避免遞歸:
讓我們先從一個虛表和數據第一:
create table t42 (DEPT number, ID number, ICCODE varchar2(2), OTHER_FIELDS varchar2(10));
insert into t42 (dept, id, iccode, other_fields) values (10, 1, 'FA', 'Data1');
insert into t42 (dept, id, iccode, other_fields) values (20, 2, 'FA', 'Data2');
insert into t42 (dept, id, iccode, other_fields) values (30, 3, 'FA', 'Data3');
insert into t42 (dept, id, iccode, other_fields) values (40, 4, 'XY', 'Data4');
沒有觸發,更新一行,如:
update t42 set iccode = 'AF' where id = 1;
將只設置單行的價值AF。使用複合觸發器來操縱集合,您可以從語句後觸發器更新,但這會被遞歸調用。
所以這裏採用dbms_application_info
(或其他機構)看到更新是否從觸發器來本身,還是從別的地方:
create or replace trigger test_trigger
for update of iccode on t42
compound trigger
-- collection to hold old and new values
type t_changed_row is record (old_value t42.iccode%type, new_value t42.iccode%type);
type t_changed_rows is table of t_changed_row;
l_changed_rows t_changed_rows := t_changed_rows();
l_fixed_info constant varchar2(30) := 'compound trigger hack';
after each row is
l_info varchar2(30);
begin
dbms_application_info.read_client_info(l_info);
if l_info is null or l_info != l_fixed_info then
-- not in nested update; store old and new values
l_changed_rows.extend;
l_changed_rows(l_changed_rows.count).old_value := :old.iccode;
l_changed_rows(l_changed_rows.count).new_value := :new.iccode;
end if;
end after each row;
after statement is
l_old_info varchar2(30);
begin
-- could check current value here as well but may not be worth it;
-- the collection will be empty anyway on second-level hit
-- store existing value to restore later
dbms_application_info.read_client_info(l_old_info);
-- set info to block recursion
dbms_application_info.set_client_info(l_fixed_info);
-- update table based on all old/new value pairs at once
forall i in 1..l_changed_rows.count
update t42
set iccode = l_changed_rows(i).new_value
where iccode = l_changed_rows(i).old_value;
-- reset info
dbms_application_info.set_client_info(l_old_info);
end after statement;
end test_trigger;
/
而這現在更新所有的匹配值:
update t42 set iccode = 'AF' where id = 1;
1 row updated.
select * from t42;
DEPT ID IC OTHER_FIEL
---------- ---------- -- ----------
10 1 AF Data1
20 2 AF Data2
30 3 AF Data3
40 4 XY Data4
儘管只有一行顯然正在更新,但所有的FA值都已更改爲AF。
修復數據模型仍然會好得多,但這種方法可能會作爲解決您的限制的解決方法。
你當前的觸發器是什麼樣的?你真的遇到了一個死鎖,或者一個變異的表錯誤,這是非常不同的? –
陷入僵局。最初得到了突變表錯誤,然後我使用了pragma autonomous_transaction;修復它並得到死鎖錯誤。 – Bujji