Oracle 更新插入触发器错误 "ORA-00036: maximum number of recursive SQL levels (50) exceeded"

Oracle upsert trigger error "ORA-00036: maximum number of recursive SQL levels (50) exceeded"

我一直在研究一个简单的更新插入触发器,它使用与名为 vibki 的列相关的唯一索引。

Table 便于访问的 DLL 信息:

  CREATE TABLE "D2C_EVENT_GENERATION_BOM" 
   (    "VIBKI" VARCHAR2(40 BYTE), 
    "STATUS" VARCHAR2(100 BYTE), 
    "LASTRUNTIME" DATE
   );
CREATE UNIQUE INDEX "D2C_EVENT_GENERATION_BOM_IND" ON ."D2C_EVENT_GENERATION_BOM" ("VIBKI");
--------------------------------------------------------
--  Constraints for Table D2C_EVENT_GENERATION_BOM
--------------------------------------------------------

ALTER TABLE "D2C_EVENT_GENERATION_BOM" MODIFY ("VIBKI" NOT NULL ENABLE);

这是我的触发器 PL/SQL :

create or replace TRIGGER "BL_D2C_EVENT_GENERATION_BOM" 
BEFORE INSERT
   ON D2C_EVENT_GENERATION_BOM REFERENCING NEW AS NEW OLD AS OLD 
FOR EACH ROW
BEGIN
    UPDATE D2C_EVENT_GENERATION_BOM SET vibki = :NEW.vibki, status = 'NEW', lastruntime = sysdate
            WHERE vibki = :NEW.vibki;
        IF ( sql%notfound ) THEN
            INSERT INTO D2C_EVENT_GENERATION_BOM (vibki,status,lastruntime)
            VALUES (:NEW.vibki,'NEW',sysdate);
    END IF;
END;

看起来很简单,我只是先尝试​​更新,如果没有找到请补充。

但是这个触发器不适用于这个插入语句:

INSERT INTO D2C_EVENT_GENERATION_BOM (vibki) VALUES ('TAS2002/01');

异常:

Error starting at line : 1 in command -
INSERT INTO D2C_EVENT_GENERATION_BOM (vibki) VALUES ('TAS2002/01')
Error report -
ORA-00036: maximum number of recursive SQL levels (50) exceeded
ORA-00036: maximum number of recursive SQL levels (50) exceeded

有人可以支持我如何实现这个错误,我在另一个 table 上使用相同的触发器,唯一的区别是我在 upsert 操作之前进行了 select 操作以收集一些值,所以我希望这段代码能够轻松工作,但它不起作用。

任何帮助将不胜感激,非常感谢!

首先 sql%rowcount 而不是 sql%notfound。对于更新 sql%notfound 总是错误的。
其次你的触发器是递归的。
触发器开启 table D2C_EVENT_GENERATION_BOM
1. 如果 sql%rowcount =0 则插入 D2C_EVENT_GENERATION_BOM
2. 为插入执行触发器(从点 1 开始)并且仍然存在 sql%rowcount = 0 然后插入 ...

并且这个模式重复了 50 次。

要修复它,您必须通知下一个触发器来中断递归。 最简单的方法是添加前缀并检查它。

create or replace TRIGGER "BL_D2C_EVENT_GENERATION_BOM" 

    BEFORE INSERT
       ON D2C_EVENT_GENERATION_BOM REFERENCING NEW AS NEW OLD AS OLD 
    FOR EACH ROW
    BEGIN
      if :NEW.vibki not like '-%' then  
        UPDATE D2C_EVENT_GENERATION_BOM SET vibki = :NEW.vibki, status = 'NEW', lastruntime = sysdate
                WHERE vibki = :NEW.vibki;            
            IF ( sql%rowcount = 0 ) THEN
                INSERT INTO D2C_EVENT_GENERATION_BOM (vibki,status,lastruntime)
                VALUES ('-'||:NEW.vibki,'NEW',sysdate);
        END IF;
      else 
       :NEW.vibki := substr(:NEW.vibki,2);
      end if; 
    END;

带有视图和触发器的解决方案 2)

create view V_D2C_EVENT_GENERATION_BOM as (select * from  D2C_EVENT_GENERATION_BOM);

CREATE OR REPLACE TRIGGER T_D2C_EVENT_GENERATION_BOM
INSTEAD OF INSERT
ON V_D2C_EVENT_GENERATION_BOM
FOR EACH ROW
begin 
   UPDATE D2C_EVENT_GENERATION_BOM SET vibki = :NEW.vibki, status = 'NEW', lastruntime = sysdate
            WHERE vibki = :NEW.vibki;
        IF ( sql%rowcount = 0 ) THEN
            INSERT INTO D2C_EVENT_GENERATION_BOM (vibki,status,lastruntime)
            VALUES (:NEW.vibki,'NEW',sysdate);
    END IF;  
end;

INSERT INTO V_D2C_EVENT_GENERATION_BOM (vibki) VALUES ('11TAS2002/01');

解决方案 3) 需要合并 0 个触发器

merge into D2C_EVENT_GENERATION_BOM a
 using (select 'your_id' vibki  from dual) b on (a.vibki =b.vibki)
WHEN MATCHED THEN 
 UPDATE set status = 'NEW', lastruntime = sysdate
            WHERE a.vibki = b.vibki
WHEN not MATCHED THEN 
 insert (vibki) values( b.vibki)         ;

您的触发器有几个问题:

  • 对于 BEFORE INSERT 触发器,您不能有任何 OLD 值。

  • UPDATE [...] SET vibki = :NEW.vibki [...] WHERE vibki = :NEW.vibki好像没用

  • IF sql%notfound THEN 在这种情况下永远不会为真。

我不知道你想达到什么目的,但可能只是

create or replace TRIGGER BL_D2C_EVENT_GENERATION_BOM
   BEFORE INSERT ON D2C_EVENT_GENERATION_BOM 
   FOR EACH ROW
BEGIN
    :NEW.status := 'NEW';
    :NEW.lastruntime := sysdate;
END;

REFERENCING NEW AS NEW OLD AS OLD是默认的,可以跳过