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
是默认的,可以跳过
我一直在研究一个简单的更新插入触发器,它使用与名为 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
是默认的,可以跳过