J'ai déjà posté ça, mais vu le manque de réaction je me demande si quelqu'un à lu et compris où est le problème.
Donc je vous proposé de reprendre la solution pour contourner l’erreur induite par la table en mutation (http://sgbd.developpez.com/oracle/ora-04091/):

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
 
CREATE TABLE CLIENT(
    IDC INTEGER PRIMARY KEY ,
    NOM VARCHAR2 (40)
    )
/
CREATE TABLE VOYAGE(
    IDV INTEGER PRIMARY KEY ,
    DESTINATION VARCHAR2 (40),
    MAXPLACE INTEGER , -- nombre total de places
    PLACEDISPO INTEGER ) -- nombre de places disponibles     
/
 
CREATE TABLE INSCRIPTION(
    IDC INTEGER REFERENCES CLIENT(IDC),
    IDV INTEGER REFERENCES VOYAGE(IDV),
    DATERESERV DATE ,
    CONSTRAINT INSCRIPTION_PK PRIMARY KEY (IDC, IDV)
)
/
INSERT INTO CLIENT(IDC, NOM) VALUES (1, 'DURAND');
INSERT INTO CLIENT(IDC, NOM) VALUES (2, 'DUBOIS');
INSERT INTO CLIENT(IDC, NOM) VALUES (3, 'DUGENOU');
COMMIT ;
 
-- un seul place disponoble pour aller à VENISE
INSERT INTO VOYAGE(IDV, DESTINATION, MAXPLACE, PLACEDISPO) VALUES (10, 'VENISE', 25, 1);
INSERT INTO VOYAGE(IDV, DESTINATION, MAXPLACE, PLACEDISPO) VALUES (11, 'PRAGUE', 20, 0);
COMMIT ;
 
-- déclencheur qui n'interroge plus la table mutante
CREATE OR REPLACE TRIGGER TRIG_INSCRIPTION BEFORE INSERT ON INSCRIPTION FOR EACH ROW
DECLARE
    NB_DISPO INTEGER ;
BEGIN
    SELECT PLACEDISPO INTO NB_DISPO FROM VOYAGE
    WHERE IDV=:NEW.IDV;
    IF NB_DISPO < 1 THEN
        DBMS_OUTPUT.PUT_LINE('Désolé, voyage complet');
    ELSE
        UPDATE VOYAGE SET PLACEDISPO=PLACEDISPO - 1
        WHERE IDV=:NEW.IDV;
    END IF ;
END ;
/
Il y a une seule modification concernant le nombre de place disponible pour aller à Venise.

Ensuite j’ouvre une première session et j'ajoute une première inscription sans faire la validation (commit) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
-- DUGENOU aimerait bien aller à Venise :
INSERT INTO INSCRIPTION(IDC, IDV, DATERESERV) SELECT 3, 10, TO_DATE(SYSDATE, 'DD/MM/YYYY') FROM DUAL ;
Dans une autre session j'ajoute une deuxième inscription pour la même destination
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
-- DUBOIS aimerait lui aussi aller à Venise :
INSERT INTO INSCRIPTION(IDC, IDV, DATERESERV) SELECT 2, 10, TO_DATE(SYSDATE, 'DD/MM/YYYY') FROM DUAL ;
Enfin je valide dans chaque session (commit) et j’interroge la table du voyage :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
 
SQL> SELECT * FROM voyage
  2  ;
 
       IDV DESTINATION                                MAXPLACE PLACEDISPO
---------- ---------------------------------------- ---------- ----------
        10 VENISE                                           25         -1
        11 PRAGUE                                           20          0
Autrement dit le trigger n'arrive pas à faire son boulot. Pour cella il faut reserver l'enregistrement de la table de voyage en mode pessimiste ou optimiste.

Il est intéressant de noter que la solution proposé par http://www.akadia.com/services/ora_m..._problems.html introduit le même type de problème.