Oracle触发错误ORA-04091

时间:2018-06-21 10:43:19

标签: sql oracle triggers database-trigger

执行触发器时出现错误(ORA-04091:表DBPROJEKT_AKTIENDEPOT.AKTIE正在变异,触发器/函数可能看不到它)

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。 您知道为什么会引发此错误吗?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您正在使用触发器修改表。使用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 :(得分:1)

这里有几个问题:

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

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

  3. 在BEFORE ROW触发器内,您可以修改:NEW行变量中字段的值以在将值写入数据库之前对其进行更改。有时候这是可以接受的,例如设置列来跟踪上次更改的时间和对象的列时,但总的来说,这是个坏主意。

好运。