复合触发器

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;