Bonjour,

J'ai des soucis avec un problème de table mutante, naturellement j'ai fait des recherches sur google et j'ai lu attentivement le tutoriel http://sgbd.developpez.com/oracle/ora-04091/

J'ai simplifié mon problème en ce que je vous expose ci-après pour faciliter la compréhension, mais il s'agît également de ce que je suis en train de tester.

Mes Tables :

etudiant (id, nom, moyenne);
matiere (id, note, id_etudiant);

Je souhaiterai calculer la moyenne d'un étudiant à chaque fois qu'une note est modifiée (imaginons que toutes les notes dont j'ai besoin sont déjà insérées et initialisées). Pour cela on m'impose l'utilisation d'un Trigger.

Mon Trigger sera appelé lors de l'utilisation d'un UPDATE de cette forme :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
UPDATE matiere SET note = 20 WHERE id = xx;
xx correspondant à l'id en base de la note modifiée.

Voici le Trigger :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
create or replace
TRIGGER TEST_TG
  AFTER UPDATE ON matiere 
   REFERENCING NEW as n
 FOR EACH ROW
 
DECLARE
  idE integer;
  moyenne_generale number;
BEGIN
 
SELECT :n.id_etudiant INTO idE FROM dual;
 
        SELECT AVG(note) INTO moyenne_generale
          FROM matiere
          WHERE id_etudiant = idE;
 
      UPDATE etudiant
        SET moyenne = moyenne_generale
        WHERE id = idE;
 
END;
C'est donc là qu'apparait mon problème de table mutante, faisant un SELECT sur une table au moment où elle est modifiée.

1ere remarque : Dans le tuto Développez.com, la méthode "E-4. Je suis grand, c'est moi qui gère" me fait sortir du Trigger sans modifier la moyenne.

2eme remarque : Je préfère ne pas avoir recours aux autres méthodes de ce tutoriel (pour le moment...) pour diverses contraintes auxquelles je suis soumis.

J'ai eu accès à un code semblable au mien qui marche en utilisant une directive PRAGMA AUTONOMOUS_TRANSACTION, de plus après des recherches cette solution semble effectivement marcher, et elle m'intéresse très fortement.

J'ai donc modifié mon Trigger comme suit :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
create or replace
TRIGGER TEST_TG
  AFTER UPDATE ON matiere 
   REFERENCING NEW as n
 FOR EACH ROW
 
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
  idE integer;
  moyenne_generale number;
BEGIN
 
SELECT :n.id_etudiant INTO idE FROM dual;
 
        SELECT AVG(note) INTO moyenne_generale
          FROM matiere
          WHERE id_etudiant = idE;
 
      UPDATE etudiant
        SET moyenne = moyenne_generale
        WHERE id = idE;
COMMIT;
END;
Et là arrive ma véritable question : ce trigger a les mêmes effets qu'un BEFORE UPDATE, c'est à dire que la moyenne calculée est celle qui était vraie avant la modification d'une des notes.
J'ai essayé de déplacer le COMMIT dans le trigger, et de le mettre partout dans le trigger (), même résultat.

J'aimerais donc savoir si il y avait une explication à ce phénomène et si je pouvais y remédier (en gardant la solution des transactions autonomes qui semble marcher dans le même cas de figure sur d'autres applications...).

Maintenant si vous me déconseillez cette méthode (même si jamais j'arrivai à la faire marcher), j'aimerai également savoir pourquoi (sachant qu'il s'agît d'une application multi-thread)

Merci d'avance pour vos conseils