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

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

解决ORA-04091行触发器中访问变异表的难题CREATE OR REPLACE TRIGGER TR_BOM_AUTONUMBER_SEQNUMBER
解决ORA-04091行触发器中访问变异表的难题BEFORE 
INSERT
解决ORA-04091行触发器中访问变异表的难题
ON BOM 
解决ORA-04091行触发器中访问变异表的难题REFERENCING NEW 
AS NEW OLD AS OLD
解决ORA-04091行触发器中访问变异表的难题
FOR EACH ROW
解决ORA-04091行触发器中访问变异表的难题
DECLARE
解决ORA-04091行触发器中访问变异表的难题    tmpVar 
number;
解决ORA-04091行触发器中访问变异表的难题
BEGIN
解决ORA-04091行触发器中访问变异表的难题    tmpVar :
= 0;
解决ORA-04091行触发器中访问变异表的难题   
SELECT GREATEST(nvl(Max(to_number(SEQ_NUMBER)),0), Count(*)) + 1 INTO tmpVar FROM BOM Where BOMID=:New.BOMID;
解决ORA-04091行触发器中访问变异表的难题   :NEW. SEQ_NUMBER:
= nvl(tmpVar,1);
解决ORA-04091行触发器中访问变异表的难题
END TR_BOM_AUTONUMBER_SEQNUMBER;
解决ORA-04091行触发器中访问变异表的难题

由于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之间及用户之间的并发冲突。

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

详细代码如下:

解决ORA-04091行触发器中访问变异表的难题CREATE OR REPLACE PACKAGE BOM_AUTONUMBER
解决ORA-04091行触发器中访问变异表的难题
IS
解决ORA-04091行触发器中访问变异表的难题TYPE t_MAX_SEQNUMBER 
is table of number INDEX BY PLS_INTEGER;
解决ORA-04091行触发器中访问变异表的难题v_MAX_SEQNUMBER t_MAX_SEQNUMBER;
解决ORA-04091行触发器中访问变异表的难题
end BOM_AUTONUMBER;
解决ORA-04091行触发器中访问变异表的难题
/解决ORA-04091行触发器中访问变异表的难题
解决ORA-04091行触发器中访问变异表的难题CREATE OR REPLACE TRIGGER TR_BOM_AUTONUMBER_SEQNUMBER
解决ORA-04091行触发器中访问变异表的难题BEFORE 
INSERT
解决ORA-04091行触发器中访问变异表的难题
ON BOM 
解决ORA-04091行触发器中访问变异表的难题REFERENCING NEW 
AS NEW OLD AS OLD
解决ORA-04091行触发器中访问变异表的难题
FOR EACH ROW
解决ORA-04091行触发器中访问变异表的难题
DECLARE
解决ORA-04091行触发器中访问变异表的难题    vNumber 
number;
解决ORA-04091行触发器中访问变异表的难题    vBOMID 
number;
解决ORA-04091行触发器中访问变异表的难题
BEGIN
解决ORA-04091行触发器中访问变异表的难题    vNumber:
= 0;
解决ORA-04091行触发器中访问变异表的难题    vBOMID:
= :New.BOMID;
解决ORA-04091行触发器中访问变异表的难题    
if not BOM_AUTONUMBER.v_MAX_SEQNUMBER.EXISTS(vBOMID) then
解决ORA-04091行触发器中访问变异表的难题        
SELECT GREATEST(nvl(Max(to_number(SEQ_NUMBER)),0), Count(*)) INTO vNumber FROM BOM Where ITEM = vBOMID;
解决ORA-04091行触发器中访问变异表的难题        BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID) :
= nvl(vNumber, 0);
解决ORA-04091行触发器中访问变异表的难题    
end if;
解决ORA-04091行触发器中访问变异表的难题    BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID) :
= BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID) + 1;
解决ORA-04091行触发器中访问变异表的难题   :NEW.SEQ_NUMBER :
= BOM_AUTONUMBER.v_MAX_SEQNUMBER(vBOMID);
解决ORA-04091行触发器中访问变异表的难题
END TR_BOM_ AUTONUMBER_SEQNUMBER;
解决ORA-04091行触发器中访问变异表的难题
/

相关文章:

  • 2022-12-23
  • 2021-09-18
  • 2021-06-26
  • 2022-02-08
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2023-02-10
猜你喜欢
  • 2021-11-30
  • 2021-12-09
  • 2021-11-13
  • 2021-11-15
  • 2021-07-29
  • 2021-06-15
相关资源
相似解决方案