Oracle upsert触发器错误“ORA-00036:超出最大递归SQL级别数(50)”

时间:2018-03-08 13:11:46

标签: oracle plsql triggers upsert

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

表格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语句:

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

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

任何帮助都会受到赞赏,非常感谢!

2 个答案:

答案 0 :(得分:3)

首先sql%rowcount代替sql%notfound。对于更新sql%notfound alwasy是假的 其次,你的触发器是递归的 触发位于表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)         ;

答案 1 :(得分:0)

您的触发器有几个问题:

  • 对于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是默认设置,因此您可以跳过它。