复合触发器
Compound Triggers
问题 - 想通过使用复合触发器来避免突变触发器的问题。但是做不到
背景 -
每当 Main table "CUSTOM_ITEM"
发生变化时,我想在新的 table“Tracking Table”中插入数据
设计是这样的,每次在 table 中创建一行时都会生成一个 ITEM_ID,但在某些情况下有一列 FIRST_ITEM_ID 保持不变。
所以每当添加新行时,我想检查它的 FIRST_ITEM_ID 然后检查整个 table 并找出所有具有相同 FIRST_[ 的 ITEM_ID =26=].
我想使用触发器将所有这些行插入到新 table 中。
这可能吗?
附加触发器:
CREATE OR REPLACE TRIGGER APP.TEST_TRG
FOR DELETE OR INSERT OR UPDATE
ON APP.CUSTOM_ITEM
COMPOUND TRIGGER
TYPE t_change_tab IS TABLE OF APP.TEST_TRG.OBJECT_ID%TYPE;
g_change_tab t_change_tab := t_change_tab();
BEFORE EACH ROW IS
BEGIN
Select item_id bulk collect into g_change_tab from CUSTOM_ITEM where first_item_id =
(Select first_item_id from CUSTOM_ITEM where item_id = :NEW.item_id);
For i in 1 .. g_change_tab.COUNT()
LOOP
g_change_tab.extend;
END LOOP;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
For i in 1 .. g_change_tab.COUNT()
LOOP
app.bc_acs_pkg.populate_TEST_TRG /* Package Inserts data */
(p_object_type => 'ITEM',
p_object_id => g_change_tab(i));
END LOOP;
g_change_tab.delete;
END AFTER STATEMENT;
END ;
/
你可以做你想做的,而不是用你现在的方法。让我们退后一步。什么是变异 table 异常 (ORA-04091)。当您尝试访问触发器在行级别事件中触发的 table 时抛出,这是不允许的。仅仅创建一个复合触发器并不能消除该限制。因此,在您的 Before Row 段中,语句
Select item_id
bulk collect into g_change_tab
from CUSTOM_ITEM where first_item_id =
(Select first_item_id from CUSTOM_ITEM where item_id = :NEW.item_id);
无效,并导致引发 ORA-04091。您需要的是使用必要的 ID 构建您的 collection。然后在 After 语句段中处理它们。
create or replace trigger test_trg
for delete or insert or update
on custom_item
compound trigger
type t_change_tab is
table of custom_item.first_item%type;
g_change_tab t_change_tab := t_change_tab();
before each row is
l_first_item_exists boolean := false;
indx integer;
begin
indx := g_change_tab.first;
while not l_first_item_exists
and indx is not null
loop
l_first_item_exists := (g_change_tab(indx) = :new.first_item);
if not l_first_item_exists
then
indx := g_change_tab.next(indx);
end if;
end loop;
if not l_first_item_exists
then
g_change_tab.extend;
g_change_tab(g_change_tab.last) := :new.first_item;
end if;
end before each row;
after statement is
begin
for indx in g_change_tab.first .. g_change_tab.last
loop
insert into tracking_table(item_id, first_item)
select item_id, first_item
from custom_item
where first_item = g_change_tab(indx);
end loop;
end after statement;
end test_trg;
这里的问题是循环,总是处理最慢,而且触发器非常糟糕。下面是一种完全避免它们的方法。但是,它确实需要在架构级别创建类型数组。
create or replace type custom_item_change_t is
table of integer ; --custom_item.first_item%type;
create or replace trigger test_trg
for insert
on custom_item
compound trigger
g_change_tab custom_item_change_t := custom_item_change_t();
before each row is
begin
g_change_tab.extend;
g_change_tab(g_change_tab.last) := :new.first_item;
end before each row;
after statement is
begin
insert into tracking_table(item_id, first_item)
select item_id, first_item
from custom_item ci
where first_item in (select distinct column_value
from table(g_change_tab)
)
and not exists
( select null
from tracking_table tt
where ci.item_id = tt.item_id
and ci.first_item = tt.first_item
);
end after statement;
end test_trg;
问题 - 想通过使用复合触发器来避免突变触发器的问题。但是做不到
背景 - 每当 Main table "CUSTOM_ITEM"
发生变化时,我想在新的 table“Tracking Table”中插入数据设计是这样的,每次在 table 中创建一行时都会生成一个 ITEM_ID,但在某些情况下有一列 FIRST_ITEM_ID 保持不变。
所以每当添加新行时,我想检查它的 FIRST_ITEM_ID 然后检查整个 table 并找出所有具有相同 FIRST_[ 的 ITEM_ID =26=].
我想使用触发器将所有这些行插入到新 table 中。
这可能吗?
附加触发器:
CREATE OR REPLACE TRIGGER APP.TEST_TRG
FOR DELETE OR INSERT OR UPDATE
ON APP.CUSTOM_ITEM
COMPOUND TRIGGER
TYPE t_change_tab IS TABLE OF APP.TEST_TRG.OBJECT_ID%TYPE;
g_change_tab t_change_tab := t_change_tab();
BEFORE EACH ROW IS
BEGIN
Select item_id bulk collect into g_change_tab from CUSTOM_ITEM where first_item_id =
(Select first_item_id from CUSTOM_ITEM where item_id = :NEW.item_id);
For i in 1 .. g_change_tab.COUNT()
LOOP
g_change_tab.extend;
END LOOP;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
For i in 1 .. g_change_tab.COUNT()
LOOP
app.bc_acs_pkg.populate_TEST_TRG /* Package Inserts data */
(p_object_type => 'ITEM',
p_object_id => g_change_tab(i));
END LOOP;
g_change_tab.delete;
END AFTER STATEMENT;
END ;
/
你可以做你想做的,而不是用你现在的方法。让我们退后一步。什么是变异 table 异常 (ORA-04091)。当您尝试访问触发器在行级别事件中触发的 table 时抛出,这是不允许的。仅仅创建一个复合触发器并不能消除该限制。因此,在您的 Before Row 段中,语句
Select item_id
bulk collect into g_change_tab
from CUSTOM_ITEM where first_item_id =
(Select first_item_id from CUSTOM_ITEM where item_id = :NEW.item_id);
无效,并导致引发 ORA-04091。您需要的是使用必要的 ID 构建您的 collection。然后在 After 语句段中处理它们。
create or replace trigger test_trg
for delete or insert or update
on custom_item
compound trigger
type t_change_tab is
table of custom_item.first_item%type;
g_change_tab t_change_tab := t_change_tab();
before each row is
l_first_item_exists boolean := false;
indx integer;
begin
indx := g_change_tab.first;
while not l_first_item_exists
and indx is not null
loop
l_first_item_exists := (g_change_tab(indx) = :new.first_item);
if not l_first_item_exists
then
indx := g_change_tab.next(indx);
end if;
end loop;
if not l_first_item_exists
then
g_change_tab.extend;
g_change_tab(g_change_tab.last) := :new.first_item;
end if;
end before each row;
after statement is
begin
for indx in g_change_tab.first .. g_change_tab.last
loop
insert into tracking_table(item_id, first_item)
select item_id, first_item
from custom_item
where first_item = g_change_tab(indx);
end loop;
end after statement;
end test_trg;
这里的问题是循环,总是处理最慢,而且触发器非常糟糕。下面是一种完全避免它们的方法。但是,它确实需要在架构级别创建类型数组。
create or replace type custom_item_change_t is
table of integer ; --custom_item.first_item%type;
create or replace trigger test_trg
for insert
on custom_item
compound trigger
g_change_tab custom_item_change_t := custom_item_change_t();
before each row is
begin
g_change_tab.extend;
g_change_tab(g_change_tab.last) := :new.first_item;
end before each row;
after statement is
begin
insert into tracking_table(item_id, first_item)
select item_id, first_item
from custom_item ci
where first_item in (select distinct column_value
from table(g_change_tab)
)
and not exists
( select null
from tracking_table tt
where ci.item_id = tt.item_id
and ci.first_item = tt.first_item
);
end after statement;
end test_trg;