INSERT触发器,用于在同一个表中插入记录

时间:2011-11-17 12:37:49

标签: oracle triggers insert mutating-table

我有一个触发器,因为我想在同一张表中插入新记录,因此在表格中插入新记录时会触发。
我的触发器是:

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作为数据库

3 个答案:

答案 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表中插入额外的行,而是使用包含数据的详细信息表。然后,触发器可以将所有必需的行插入到详细信息表中。

如果两个表之间存在删除级联外键关系,则可能会再次遇到变异触发器错误,因此最好避免这种情况。