执行触发时出错

时间:2014-01-03 14:36:22

标签: oracle plsql triggers

我正在制作航班预订系统并尝试在将航班分配到航班之前验证飞机可用性,我正在使用Apex并使用触发器执行此操作。触发器在插入情况下工作但是在更新的情况下我收到了错误。

错误:

    •ORA-04091: table FLIGHT is mutating, trigger/function may not see it ORA-06512: at
 "VALIDATEPLANE", line 2 ORA-04088: error during execution of trigger 'VALIDATEPLANE'

守则:

create or replace trigger "VALIDATEPLANE"
before
insert or update on "FLIGHT"
for each row
begin
    for index1 in(select * from FLIGHT)
    loop
        if :new.PLANE_NO = index1.PLANE_NO 
        then
            if :new.DEPARTUAL_DATE <index1.DEPARTUAL_DATE 
               or :new.DEPARTUAL_DATE > index1.DEPARTUAL_DATE
            then 
                if :new.ARRIVE_DATE<=index1.ARRIVE_DATE
                then
                    :new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE);
                    :new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1;
                end if;
            ELSIF :new.DEPARTUAL_DATE =index1.DEPARTUAL_DATE
            then 
                :new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE);
                :new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1;
            end if;
        end if;
     end loop;
end;

3 个答案:

答案 0 :(得分:3)

触发器不是一个好工具。触发语句可以插入多行,它可以使用多个并行线程来插入。因此,数据库无法保证在插入期间返回一致的行集:数据库可以在字面上同时插入多行。为了保护您,数据库返回一个变异错误。

此处对于每个插入的行,您将逐行查询整个表格(Schlemiel the painter's algorithm的完美示例)。

通常,将复杂的业务规则放在触发器中是一个坏主意,因为:

  • 生成的代码是碎片化的(业务规则与实际插入分开)
  • 因此它以隐藏的方式修改DML的标准行为
  • 多个触发器相互交互的逻辑难以预测,并且难以诊断错误
  • 您不能在行触发器中使用set logic,因此大多数情况下代码都是次优的。

如果你遇到一个变异错误并且坚持使用触发器,这里有一个你需要跳过的箍的例子:Avoiding mutating errors by Tom Kyte

我建议你改用PL / SQL程序。它们更易于编码,读取和维护。它们可以逻辑地分组在一个非常独立的包中。您将更容易使用设置逻辑,逐行逻辑的性能提升可能是至关重要的。

答案 1 :(得分:0)

当您触发插入语句时,例如INSERT INTO TABLE VALUES (),您确定要插入一行。

但是当你UPDATEMERGE时,BEFORE INSERT触发器知道它只针对第一行触发。但实际上,它无法获得稳定的行集。尝试重新处理受影响的行集。

答案 2 :(得分:0)

无法对已触发触发器的表执行DML操作。在这种情况下,您已在表FLIGHT上创建了触发器并从同一个表中获取数据,即FLIGHT。

插入操作正在运行,因为它是一个before触发器,并且没有触发在表中尚未创建的行上触发器的逻辑。如果它是后触发器,那么在插入操作期间也会遇到相同的错误。

一种解决方案可能是引入一个保存类似于FLIGHT表的记录的并行表,您可以从该表中选择数据以便在触发器中进行比较。您只能在此触发器内将数据插入该表。但你应该避免这样的解决方案。