今天看Oracle® Database PL/SQL Language Reference 11g Release 2 (11.2),对Compound DML Triggers写了一些学习的测试脚本。
背景:如果在触发器里对触发器所在表进行DML,会报ORA-04091表变异的错误。
测试如下:
建表:create table ABC_TEST
(
zonecode VARCHAR2(14),
disease_id1 NUMBER(4) not null,
intime DATE,
casetype VARCHAR2(1),
casetype2 VARCHAR2(1),
dead NUMBER
)
普通的DML触发器:CREATE OR REPLACE TRIGGER log_deletions_1
AFTER insert ON abc_test
FOR EACH ROW
DECLARE
n INTEGER;
BEGIN
SELECT COUNT(*) INTO n FROM abc_test; --这句是重点,报错就是这句引起的
DBMS_OUTPUT.PUT_LINE('There are now ' || n || ' employees.');
END;
插入记录:
SQL> insert into ABC_TEST values('43012200',198,sysdate,1,1,2);
insert into ABC_TEST values('43012200',198,sysdate,1,1,2)
ORA-04091: table HR.ABC_TEST is mutating, trigger/function may not see it
ORA-06512: at "HR.LOG_DELETIONS_1", line 4
ORA-04088: error during execution of trigger 'HR.LOG_DELETIONS_1'
如果一定要在触发器查询自己,可以建成复合触发器,如下:
CREATE OR REPLACE TRIGGER log_deletions
FOR insert ON abc_test
COMPOUND TRIGGER --这个是关键字哦
n INTEGER;
BEFORE STATEMENT IS --插入前查一遍表,这个会在insert之前执行
begin
SELECT COUNT(1) INTO n FROM abc_test;
DBMS_OUTPUT.PUT_LINE('There are now ' || n || ' employees.');
END BEFORE STATEMENT;
AFTER STATEMENT IS --插入后执行,这个会在insert之后执行
BEGIN
SELECT COUNT(1) INTO n FROM abc_test;
DBMS_OUTPUT.PUT_LINE('There are now ' || n || ' employees.');
END AFTER STATEMENT;
END;
SQL> insert into ABC_TEST values('43012200',198,sysdate,1,1,2);
There are now 0 employees.
There are now 1 employees.
1 row inserted
SQL> commit;
Commit complete
看到效果了吧。复合触发器,能在触发器之前,先对表进行查询,在插入后,可以马上看到插入的行,神奇吧。
好了,今天就写到这,学习到compound trriger 的特性。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25027760/viewspace-764589/
,如需转载,请注明出处,否则将追究法律责任。