我一直在研究一个简单的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操作之前收集一些值,所以我希望这段代码能够轻松工作但是它不起作用。
任何帮助都会受到赞赏,非常感谢!
答案 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
是默认设置,因此您可以跳过它。