web-dev-qa-db-ja.com

ORA-04091変異トリガーエラーの修正方法がわかりません

私はOracle SQLを学習していますが、トリガーを処理しているときにエラーが見つかり、そのテーブルの値を更新できません。

エラーは:

エラーORA-04091:テーブルUSUARIO.LINEASは変化し、トリガー/関数はそれを表示しない可能性がありますORA-06512: "USUARIO.TRG_ACTUALIZARPEDIDO"、5行目ORA-04088:トリガー 'USUARIO.TRG_ACTUALIZARPEDIDO'の実行中にエラーが発生しました

私はそれについて学びましたが、解決策を見つけることも、自分で何が問題なのかを理解することもできません。

CREATE OR REPLACE TRIGGER trg_actualizarpedido
AFTER INSERT OR UPDATE OR DELETE ON LINEAS
FOR EACH ROW

DECLARE
    sumaImporteLineas NUMBER := 0;

BEGIN
    SELECT SUM(IMPORTE) INTO sumaImporteLineas FROM LINEAS WHERE NUMPEDIDO = :NEW.NUMPEDIDO;
    UPDATE PEDIDOS ped SET ped.TOTAL = sumaImporteLineas WHERE ped.NUM = :NEW.NUMPEDIDO;
END;

ありがとう!

3

ORA-04091

これはOracleの言い方です。

あなたは本当にそれをしたくないのです。

これが私の回避策のリストです。

オプション1

VIEWを使用します。

これは推奨される方法です。

オプション2

使う Materialized View

はい、コミット時にSUM()を高速リフレッシュできます。

オプション3

TAPI(テーブルAPI)を使用します。 (a Package

すべてのDML操作はこのPackageを経由する必要があります。実際のテーブルに決して反対しないでください。

オプション4

3-トリガーソリューション。 (これは単一のComplexトリガーである可能性があります。)

適切にロックしないと、「更新が失われる」可能性があります。

適切にロックしても、デッドロックが発生する可能性があります。

1
Michael Kutz

テーブルへの変更に反応するトリガー内では、テーブル自体をクエリすることはできません。しかし、その必要はありません。

IMPORTEの値の変更に基づいて現在の合計を維持しようとしているように見えます。そのためには、1つではなくthreeトリガーが必要です。

/* Insert - Add New value */ 
CREATE OR REPLACE TRIGGER trg_actualizarpedido1
AFTER INSERT ON LINEAS
FOR EACH ROW
BEGIN
    UPDATE PEDIDOS 
    SET TOTAL = TOTAL + :NEW.IMPORTE 
    WHERE NUMPEDIDO = :NEW.NUMPEDIDO ; 
END;

/* Update - Subtract the Old value, Add New value */ 
CREATE OR REPLACE TRIGGER trg_actualizarpedido2
AFTER UPDATE ON LINEAS
FOR EACH ROW
BEGIN
    UPDATE PEDIDOS 
    SET TOTAL = TOTAL - :OLD.IMPORTE + :NEW.IMPORTE 
    WHERE NUMPEDIDO = :NEW.NUMPEDIDO ; 
END;

/* Delete - Subtract the Old value */ 
CREATE OR REPLACE TRIGGER trg_actualizarpedido3
AFTER DELETE ON LINEAS
FOR EACH ROW
BEGIN
    UPDATE PEDIDOS 
    SET TOTAL = TOTAL - :OLD.IMPORTE 
    WHERE NUMPEDIDO = :OLD.NUMPEDIDO ; 
END;
0
Phill W.

他の回答ですでに与えられているように、そのようなタスクのトリガーを使用することは、それを行うための好ましい方法ではありません。ここで完全を期すために、トリガーベースのソリューション(テストされていません):

create or replace trigger trg_actualizarpedido
  for insert or update or delete on LINEAS 
  COMPOUND TRIGGER

  type NUMPEDIDO_t is table of LINEAS.NUMPEDIDO%type;
  NUMPEDIDOs NUMPEDIDO_t ;
  sumaImporteLineas NUMBER;

  before statement is 
  begin
    NUMPEDIDOs := NUMPEDIDO_t();
  end before statement;

  after each row is 
  begin
    NUMPEDIDOs.EXTEND;
    IF INSERTING OR UPDATING ('NUMPEDIDO') THEN
       NUMPEDIDOs(NUMPEDIDOs.LAST) := :NEW.NUMPEDIDO;
    ELSIF DELETING THEN
       NUMPEDIDOs(NUMPEDIDOs.LAST) := :OLD.NUMPEDIDO;
    END IF;
  end after each row;

  after statement is 
  begin      
    for i in NUMPEDIDOs.FIRST..NUMPEDIDOs.LAST LOOP
       SELECT SUM(IMPORTE) INTO sumaImporteLineas 
       FROM LINEAS 
       WHERE NUMPEDIDO = NUMPEDIDOs(i);

       UPDATE PEDIDOS ped SET ped.TOTAL = sumaImporteLineas 
       WHERE ped.NUM = NUMPEDIDOs(i);
    end loop;          
  end after statement;

end;
0