我在表格中有以下数据
DEPT ID ICCODE OTHER FIELDS
==== === ===== ============
10 2 FA Data1
20 2 FA Data2
30 2 FA Data3
每个部门都属于某个外部应用程序。如果任何外部应用程序更改任何部门的ICCODE,我应该更新具有相同值的其他两个部门ICCODE。
我正在列ICCODE上写一个触发器并更新其他两个记录,但问题是触发器位于同一列上,并且在触发器中为不同的行再次修改相同的列值。它造成了僵局。请问任何人请让我知道解决方案或任何变通方法?我无法更改上表的结构,但如果需要可以创建新表。这里的问题是外部应用程序只更新此表...
此致
答案 0 :(得分:1)
您的数据模型是一个问题,因为它应该像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。使用复合触发器来操作集合,您可以从after语句触发器更新,但这将以递归方式调用。
所以这使用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。
修复数据模型仍然会好得多,但考虑到您的限制,这种方法可能会作为一种解决方法。