如何解决触发器中的变异表错误?

时间:2018-10-29 06:31:28

标签: oracle database-trigger

我有两个表,名称分别为itemstock_item。 当我更新item表时,将触发名称为beforeItem的触发器,这将从qty中减去新的更新后的stock_qty。但是它会抛出

  

ORA-04091:表****正在突变触发器/功能可能看不到

我该如何解决?

我的桌子:

create table stock_item
(no number primary key,itemName varchar2(10),stock_Qty number);

create table item 
(no number,Name varchar2(10),qty number);   

我的触发器

create or replace trigger beforeItem
before update on item
for each row 
declare 
chk_no number;
chk_item varchar2(10);
chk_qty number;
--pragma AUTONOMOUS_TRANSACTION;
-- this code will skip the update code.
begin
select no,name,qty into chk_no, chk_item,chk_qty from item where  no=:new.no 
and name=:new.name;
update stock_item set itemName = itemName - chk_qty where no=chk_no and 
itemName=chk_item; 
--commit;
end; 

2 个答案:

答案 0 :(得分:0)

当触发器针对拥有该触发器的表发出DML时,Oracle催促ORA-04091;这包括SELECT语句。原因很简单:表的状态未知,因为触发器在事务期间触发 ,因此触发器DML的结果是不可预测的。

解决方案通常很简单:删除DML。这肯定是这里的答案,因为您的:NEW记录具有在stock_item上执行更新所需的所有值:

create or replace trigger beforeItem
    before update on item
    for each row 
 begin

    update stock_item si
    set si.stock_Qty = si.stock_Qty - :new.qty 
    where si.no = :new.no; 

end; 
  

但是stock_item表不知道要减去的项目表qty的当前值是多少。

好的,也就是说,您想使用旧(当前)ITEM.QTY与新(更新)值之间的差异来更新STOCK_ITEM.QTY。那样的话:

create or replace trigger beforeItem
    before update on item
    for each row 
 begin

    update stock_item si
    set si.stock_Qty = si.stock_Qty - (nvl(:old.qty,0) - nvl(:new.qty,0)) 
    where si.no = :new.no; 

end; 

这是我在SQL Fiddle上的解决方案的演示。


顺便说一句,请注意,我已更正了您的UPDATE语句:从库存名称中减去项目数量确实没有任何意义。另外,在需要使用主键的WHERE子句中也无需使用itemName

答案 1 :(得分:0)

您不能在此触发器中引用表ITEM,因为它会导致您的错误。代替使用SELECT语句,而是使用新/旧参数。尝试使用此版本的触发器。

create or replace trigger beforeItem
  before update on item
  for each row 
begin
  -- if :new.qty is not null then
    update stock_item set 
      -- logic to maintaint if no changes on qty field were done
      stock_Qty = stock_Qty - ( nvl(:new.qty,0) - nvl(:old.qty,0) ) 
      where no=:new.no and itemName=:new.name; 
  -- end if;
end;