How to call a Procedure which uses the same table in after trigger

吃可爱长大的小学妹 提交于 2019-12-23 04:43:18

问题


I want to use the same table data after deleting the data which fails in following method.

The issue I faced is the latest change is not getting committed before the after trigger is completed.


create table test_tbl(id_ number, type_ varchar2(100) , count_ number);

create table test_count_tbl(type varchar2(100), count_ number) ; 

 begin 
    insert into test_tbl(id_ , type_  , count_ ) values (1,'type1', 10 );
    insert into test_tbl(id_ , type_  , count_ )  values (2,'type1', 20 );
    insert into test_tbl(id_ , type_  , count_ )  values (3,'type2', 10 );
    insert into test_tbl(id_ , type_  , count_ )  values (4,'type2', 40 );
    insert into test_tbl(id_ , type_  , count_ )  values (5,'type3', 10 );
    insert into test_tbl(id_ , type_  , count_ )  values (6,'type3', 60 );
    commit;
    end;

create or replace procedure test_count_update_p( p_type_ in varchar2) 
is 
begin 

  MERGE INTO test_count_tbl D
   USING (select type_, sum(count_) count_sum_
          from test_tbl
          where type_ = p_type_
          group by type_ ) S   ON (D.type = S.count_sum_)
   WHEN MATCHED THEN UPDATE SET D.count_ = S.count_sum_ 
   --  DELETE WHERE (S.salary > 8000)
   WHEN NOT MATCHED THEN INSERT (D.type, D.count_)
     VALUES (S.type_, S.count_sum_);
  commit;
end ;

 CREATE OR REPLACE TRIGGER test_tbl_trigger
    AFTER INSERT  OR DELETE OR UPDATE ON test_tbl 
    FOR EACH ROW

    DECLARE    
       PRAGMA AUTONOMOUS_TRANSACTION;    
       L_TYPE VARCHAR2(100);
    BEGIN    
        if DELETING THEN 
           L_TYPE  := :OLD.TYPE_;
           end if;

        IF UPDATING OR INSERTING THEN 
          L_TYPE  := :NEW.TYPE_;
        end if; 

       test_count_update_p(L_TYPE);    
       COMMIT;    
    END;

Do the following to see the exact issue..

begin 
insert into test_tbl(id_ , type_  , count_ )  values (7,'type4', 60 );
commit;
end;

select * from test_tbl ;

record is inserted to the table.

select * from test_count_tbl ; 

record is not counted in the this table yet.

begin 
delete test_tbl where id_ = 7;
commit ;
end;

select * from test_tbl ;

deleted the record.

select * from test_count_tbl ; 

Counted the record which is not available in the table test_tbl;


回答1:


You can't.

A normal row-level trigger cannot query the table the trigger is defined on because that would raise a mutating table exception. I'm assuming that's why you have declared your trigger to use an autonomous transaction (an autonomous transaction for anything other than persistent logging is almost certainly an error). If you do that, however, your trigger cannot see the uncommitted changes made by the triggering transaction. That's the problem you're encountering now.

An alternative would be to use a compound trigger. You'd declare a collection of test_table.type_%type, you would add the values that are changing to this collection in the row-level portion of your trigger, and then you would iterate over the elements in the collection in the after-statement portion of your trigger. A statement-level trigger is allowed to query the table on which the trigger is defined so you can call your procedure from the after-statement portion of your compound trigger.




回答2:


Your best action is to drop the TEST_COUNT_TBL table altogether. Just create a view by that name:

create view TEST_COUNT_TBL as
select type_ Type, sum( count_ ) Count
from test_tbl
group by type_;

Then you will always have accurate, up-to-date information at your beck and call but never have to worry about doing strange and wonderful things with triggers.




回答3:


Used Compound Trigger and removed PRAGMA AUTONOMOUS_TRANSACTION; as well as removed commit statements. Still committed data could access and do the calculations in an external function and write to a separate table.



来源:https://stackoverflow.com/questions/27093743/how-to-call-a-procedure-which-uses-the-same-table-in-after-trigger

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!