私は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;
ありがとう!
これはOracleの言い方です。
あなたは本当にそれをしたくないのです。
これが私の回避策のリストです。
VIEW
を使用します。
これは推奨される方法です。
使う Materialized View
。
はい、コミット時にSUM()を高速リフレッシュできます。
TAPI(テーブルAPI)を使用します。 (a Package
)
すべてのDML操作はこのPackage
を経由する必要があります。実際のテーブルに決して反対しないでください。
3-トリガーソリューション。 (これは単一のComplexトリガーである可能性があります。)
適切にロックしないと、「更新が失われる」可能性があります。
適切にロックしても、デッドロックが発生する可能性があります。
テーブルへの変更に反応するトリガー内では、テーブル自体をクエリすることはできません。しかし、その必要はありません。
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;
他の回答ですでに与えられているように、そのようなタスクのトリガーを使用することは、それを行うための好ましい方法ではありません。ここで完全を期すために、トリガーベースのソリューション(テストされていません):
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;