1

我有两个表 -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_TRANSACTIONXX_RBIU但它导致了僵局。

我也尝试参考this , this , thisthis但找不到解决方案。

任何帮助深表感谢。

4

3 回答 3

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,但是如果您出于某种原因无法重新设计解决方案,则应该可以使用。

于 2013-11-12T04:01:56.487 回答
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;
/

在 trigger 中不需要更改YY_RBIU

于 2013-11-12T06:26:22.427 回答
0

该消息是因为当您在触发器 SCMA.XX_RBIU 中插入更新表 xx 时,您还会更新表 yy,因此激活了 SCMA.YY_RBIU 触发器并从 xx 表中选择

在 pl_sql 中,它禁止同时更新/插入和选择(您在 xx 表中执行此操作)。我多次遇到这个问题,这是解决方案。再会。

于 2013-11-12T07:56:37.713 回答