我有一个触发器,因为我想在同一张表中插入新记录,因此在表格中插入新记录时会触发。
我的触发器是:
create or replace trigger inst_table
after insert on test_table referencing new as new old as old
for each row
declare
df_name varchar2(500);
df_desc varchar2(2000);
begin
df_name := :new.name;
df_desc := :new.description;
if inserting then
FOR item IN (SELECT pid FROM tbl2 where pid not in(1))
LOOP
insert into test_table (name,description,pid) values(df_name,df_desc,item.pid);
END LOOP;
end if;
end;
它给出了一个像
这样的错误 ORA-04091: table TEST_TABLE is mutating, trigger/function may not see it
我认为它阻止我插入同一张桌子 那我怎么能把这个新记录插入到同一个表中。
注意: - 我使用 Oracle作为数据库
答案 0 :(得分:10)
只要你有一个行级触发器来修改你正在触发的表,就会发生变异。问题是,Oracle无法知道如何表现。你插入一行,触发器本身会在相同的表中插入一行,并且Oracle会因为触发器而导致那些插入到表中的混乱,是否它们也受到触发操作的影响? / p>
解决方案分为三个步骤。
1。)触发器之前的语句级别,用于实例化将跟踪正在插入的行的包。
2。)触发器之前或之后的行级别,将行信息保存到上一步中实例化的包变量中。
3。)插入表中的触发器之后的语句级别,保存在包变量中的所有行。
这方面的一个例子可以在这里找到:
http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936
希望有所帮助。
答案 1 :(得分:1)
我会说你应该以任何其他方式来看待触发器以实现这一目标。正如Mark Bobak的回答中所提到的,触发器是插入一行,然后是触发器插入的每一行,然后需要调用触发器来插入更多行。
我要么编写存储过程来创建插入,要么只是通过子查询而不是值来插入。
触发器可用于解决简单问题,但在解决更复杂的问题时,它们只会引起麻烦。
值得一读的是APC发布的duplicate question的答案以及Tom Kyte的this article。顺便说一下,这篇文章也在重复的问题中引用,但链接现在已经过时了。
答案 2 :(得分:1)
虽然在抱怨触发器有多糟糕之后,这是另一种解决方案。
也许你需要看看有两张桌子。像现在一样将数据插入test_table
表。但是,不要让触发器在test_table
表中插入额外的行,而是使用包含数据的详细信息表。然后,触发器可以将所有必需的行插入到详细信息表中。
如果两个表之间存在删除级联外键关系,则可能会再次遇到变异触发器错误,因此最好避免这种情况。