问题
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