我有两个表 - XX
和YY
,如果有更新,它们的触发器会互相调用。
XX上的触发器如下:
CREATE OR REPLACE TRIGGER SCMA.XX_RBIU
BEFORE INSERT OR UPDATE
ON SCMA.XX FOR EACH ROW
-- PL/SQL BLOCK
BEGIN
IF UPDATING THEN
-- Only update the YY row if the branch id has
-- been modified on the XX row
IF :NEW.BRANCH_ID <> :OLD.BRANCH_ID THEN
UPDATE YY TP
SET TP.BRANCH_ID = :NEW.BRANCH_ID
WHERE TP.XX_ID = :NEW.XX_ID;
END IF;
END IF;
...
... -- Other PL/SQL statements that do some necessary
... -- computation and do not use any SQL.
...
END;
/
YY上的触发器是这样的:
CREATE OR REPLACE TRIGGER SCMA.YY_RBIU
BEFORE INSERT OR UPDATE
ON SCMA.YY
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
v_xx_type xx.xx_type_code%TYPE;
BEGIN
select x.xx_type_code
into v_xx_type
from XX x
where x.xx_id = :new.xx_id;
...
... -- Other PL/SQL statements that do some necessary
... -- computation and do not use any SQL.
...
END;
/
我知道触发器SELECT
中的YY_RBIU
语句会出现此错误。我如何编码我的触发器以避免它?
我尝试将SELECT
语句包含在YY_RBIU
块中的IF INSERTING THEN
内,但这不会针对任何更新运行。如果从触发器SELECT
调用更新,如何跳过此XX_RBIU
语句?
我也尝试将PRAGMA AUTONOMOUS_TRANSACTION
放入XX_RBIU
,但这会导致陷入僵局。
我还尝试引用this,this,this和this,但无法获得解决方案。
非常感谢任何帮助。
答案 0 :(得分:1)
我避免触发的几个原因之一。基本上你需要提出一个没有循环触发问题的整洁解决方案。也可以添加:
IF :NEW.BRANCH_ID <> :OLD.BRANCH_ID
也可以YY
触发器。但这可能意味着你的触发器错过了一些真正的更新。
一个可行的hacky解决方案是拥有一个新的YY_flag
表:
YY_FLAG
xx_id (Primary Key)
然后在XX
触发器中
INSERT INTO yy_flag VALUES( :new.xx_id );
UPDATE YY ...
DELETE FROM yy_flag WHERE xx_id = :new.xx_id;
在YY
触发器中
BEGIN
SELECT count(1) INTO is_trigger FROM yy_flag WHERE xx_id = :new.xx_id;
IF is_trigger = 0 THEN
SELECT FROM XX
...
所以基本上yy_flag
表只包含给定xx_id
正在执行触发器的记录。对象是永远不会向yy_flag
表提交一行,而oracle的正常锁定应该处理所有并发内容。
正如我所说,这非常hacky,但如果您因任何原因无法重新设计解决方案,那么应该会有效。
答案 1 :(得分:0)
对我来说,复合触发器起作用了。在此复合触发器中,我从UPDATE
段移除了BEFORE EACH ROW
语句并将其放入AFTER STATEMENT
段并且它有效。我使用了一个集合来保存必要的值。
这是触发器:
CREATE OR REPLACE TRIGGER SCMA.TRANSACTION_COMPOUND
FOR INSERT OR UPDATE ON SCMA.XX
COMPOUND TRIGGER
-- DECLARE GLOBAL VARIABLES THAT WOULD BE USED ACROSS
-- THE DIFFERENT EVENTS.
TYPE rec_chg_br IS RECORD (
xx_id XX.xx_id%TYPE,
branch_id jbs_branch.branch_id%TYPE
);
TYPE t_chg_br IS TABLE OF rec_chg_br
INDEX BY PLS_INTEGER;
chg_branch t_chg_br;
BEFORE EACH ROW IS
BEGIN
IF UPDATING THEN
-- Only update the YY row if the branch id has
-- been modified on the XX row
IF :NEW.BRANCH_ID <> :OLD.BRANCH_ID THEN
chg_branch(:new.xx_id).xx_id := :new.xx_id;
chg_branch(:new.xx_id).currency_id := :new.currency_id;
chg_branch(:new.xx_id).branch_id := :new.branch_id;
END IF;
END IF;
...
... -- Other PL/SQL statements that do some necessary
... -- computation and do not use any SQL.
...
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
-- NULL; -- Do something here.
FORALL i IN chg_branch.FIRST..chg_branch.LAST
UPDATE YY
SET BRANCH_ID = chg_branch(i).branch_id,
CURRENCY_ID = chg_branch(i).currency_id
WHERE xx_id = chg_branch(i).xx_id;
END AFTER STATEMENT;
END TRANSACTION_COMPOUND;
/
触发器YY_RBIU
无需更改。
答案 2 :(得分:0)
消息,因为当您插入或更新表xx时 在触发器SCMA.XX_RBIU中你还更新表yy 所以激活SCMA.YY_RBIU触发器并从xx表选择
在pl_sql中禁止更新/插入并同时选择(在xx表中执行)。 我有很多次这个问题,这是解决方案。 美好的一天。