J'apprends Oracle SQL, mais lorsque vous faites face à des déclencheurs, je trouve une erreur, cela m'empêche de mettre à jour les valeurs de cette table.
L'erreur est:
erreur ORA-04091: TABLE USUARIO.LINEAS MUTATIF.LINEASE MUTATIVE, la fonction/fonction peut ne pas la voir ORA-06512: à "usuario.trg_actualizarpedido", ligne 5 ora-04088: Erreur lors de l'exécution de la gâchette 'usuario.trg_actualizarpedido'
J'apprends à ce sujet, mais je ne trouve pas de solution ou de comprendre par moi-même quel est le problème.
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;
Merci!
C'est la manière d'Oracle de dire:
vous ne voulez vraiment pas faire ça.
Voici ma courte-liste des solutions de contournement.
Utilisez un VIEW
.
C'est la méthode préférée.
Utiliser un Materialized View
.
Oui, vous pouvez rafraîchir la SUM () sur COMMIS.
Utilisez un TAPI (API de table). (A Package
)
Toutes les opérations DML doivent parcourir ce Package
; jamais contre la table réelle.
Solution à 3 déclencheurs. (Cela pourrait être un déclencheur unique complexe.)
Sans verrouillage approprié, vous pourriez avoir des "mises à jour perdues".
Même avec un verrouillage correct, des serrures mortes pourraient se produire.
Dans une gâchette réagissant à un changement à une table, vous ne pouvez pas interroger la table elle-même. Mais vous n'avez pas besoin de.
Il semble que vous essayiez de conserver un total de fonctionnement en fonction des modifications apportées à la valeur de l'importante. Pour cela, vous n'avez pas besoin d'un mais trois déclencheurs:
/* 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;
Comme déjà donné dans les autres réponses en utilisant un déclencheur pour une telle tâche n'est pas la manière préférée de le faire. Par souci d'exhaustivité, une solution basée sur la gâchette (non testée):
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;