解决ORA-04091行触发器中访问变异表的难题

核心思路就是:在第一次插入时保存值到包变量中,第二次插入时不再读取表本身,转而读取包变量,可以成功解决这类难题。

在工作中,需要为各个BOM的每个ITEM依次自动编号,不同BOM的ITEM的SEQ_NUMBER列都要 按1.2.3…自动生成序号。
第一次,我这样写,

CREATE  OR  REPLACE  TRIGGER TR_BOM_AUTONUMBER_SEQNUMBER
BEFORE  INSERT
ON BOM 
REFERENCING NEW  AS NEW OLD  AS OLD
FOR EACH ROW
DECLARE
    tmpVar  number;
BEGIN
    tmpVar : =  0;
    SELECT GREATEST(nvl( Max(to_number(SEQ_NUMBER)), 0),  Count( *))  +  1  INTO tmpVar  FROM BOM  Where BOMID =:New.BOMID;
   :NEW. SEQ_NUMBER: = nvl(tmpVar, 1);
END TR_BOM_AUTONUMBER_SEQNUMBER;

由于Insert操作会修改表数据,所以Insert…Select插入多行数据时,会报ORA-04091: table string.string is mutating, trigger/function may not see it错误,原因在于插入第2条数据时表已修改不能再访问。

查阅了很多文章,有提示在其中使用 PRAGMA AUTONOMOUS_TRANSACTION来保证每行插入动作为自治事务。但实际上,经过我的测试,虽然DML不会出错,但实际SEQ_NUMBER全部为1,没有达到依次自动编号的目的。

经过多次试验后,我使用保存于包中的索引表保存各个BOM的最大SEQ_NUMBER,可以防止BOM之间及用户之间的并发冲突。

核心思路就是:在第一次插入时保存值到包变量中,第二次插入时不再读取表本身,转而读取包变量,可以成功解决这类难题。

详细代码如下:

CREATE  OR  REPLACE PACKAGE BOM_AUTONUMBER
IS
TYPE t_MAX_SEQNUMBER  is  table  of  number  INDEX  BY PLS_INTEGER;
v_MAX_SEQNUMBER t_MAX_SEQNUMBER;
end BOM_AUTONUMBER;
/
CREATE  OR  REPLACE  TRIGGER TR_BOM_AUTONUMBER_SEQNUMBER
BEFORE  INSERT
ON BOM 
REFERENCING NEW  AS NEW OLD  AS OLD
FOR EACH ROW
DECLARE
    vNumber  number;
    vBOMID  number;
BEGIN
    vNumber: =  0;
    vBOMID: = :New.BOMID;
     if  not BOM_AUTONUMBER.v_MAX_SEQNUMBER. EXISTS(vBOMID)  then
         SELECT GREATEST(nvl( Max(to_number(SEQ_NUMBER)), 0),  Count( *))  INTO vNumber  FROM BOM  Where ITEM  = vBOMID;
        BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID) : = nvl(vNumber,  0);
     end  if;
    BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID) : = BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID)  +  1;
   :NEW.SEQ_NUMBER : = BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID);
END TR_BOM_ AUTONUMBER_SEQNUMBER;
/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值