Oracle触发器错误ORA-04091

Oracle trigger error ORA-04091

我在执行触发器时遇到错误(ORA-04091:table DBPROJEKT_AKTIENDEPOT.AKTIE 正在发生变化,trigger/function 可能看不到它):

CREATE OR REPLACE TRIGGER Aktien_Bilanz_Berechnung
AFTER 
INSERT OR UPDATE OF  TAGESKURS
OR INSERT OR UPDATE OF  WERT_BEIM_EINKAUF
ON AKTIE
FOR EACH ROW
DECLARE
bfr number;
Begin
bfr := :new.TAGESKURS - :new.WERT_BEIM_EINKAUF;
UPDATE AKTIE
SET BILANZ = TAGESKURS - WERT_BEIM_EINKAUF;
IF bfr < -50
THEN
DBMS_OUTPUT.PUT_LINE('ACHTUNG: The value (Nr: '||:new.AKTIEN_NR||') is very low!');
END IF;
END;

我想在计算后检查值 "BILANZ",是否小于 -50。 你知道为什么会抛出这个错误吗?

感谢您的帮助!

您正在使用触发器修改 table。使用 before update 触发器:

CREATE OR REPLACE TRIGGER Aktien_Bilanz_Berechnung
BEFORE INSERT OR UPDATE OF TAGESKURS OR INSERT OR UPDATE OF  WERT_BEIM_EINKAUF
ON AKTIE
FOR EACH ROW
DECLARE
    v_bfr number;
BEGIN
    v_bfr := :new.TAGESKURS - :new.WERT_BEIM_EINKAUF;
    :new.BILANZ := v_bfr;
    IF v_bfr < -50 THEN
      Raise_Application_Error(-20456,'ACHTUNG: The value (Nr: '|| :new.AKTIEN_NR || ') is very low!');
    END IF;
END;

这里有几个问题:

  1. Oracle 不允许您在 table 上定义的行触发器或从此类触发器调用的任何代码中针对 table 执行 SELECT/INSERT/UPDATE/DELETE ,这就是为什么在 运行 时发生错误的原因。有一些方法可以解决此问题 - 例如,您可以阅读我对 and this question 的回答 - 但通常您必须避免访问 table,在触发器中定义了行触发器。

  2. 在此触发器中执行的计算是所谓的业务逻辑,不应在触发器中执行。将这样的逻辑放在触发器中,无论它看起来多么方便,最终都会让任何必须维护此代码的人感到非常困惑,因为 BILANZ 的值在阅读应用程序代码的 INSERTUPDATE 语句看不到它。此计算应在 INSERTUPDATE 语句中执行,而不是在触发器中执行。定义一个过程以在 table 上执行 INSERT/UPDATE/DELETE 操作是一种很好的做法,这样所有此类计算都可以在一个地方捕获,而不是分散在整个代码库中。

  3. 在 BEFORE ROW 触发器中,您 可以 修改 :NEW 行变量中字段的值以在写入之前更改值到数据库。有时这是 acceptable,例如在设置跟踪一行最后一次更改的时间和更改者的列时,但通常这被认为是一个坏主意。

祝你好运。