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 47 48 49 50 51 52 53 54 55 56 57 58 59
|
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
;
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 ;
INSERT INTO VOYAGE(IDV, DESTINATION, MAXPLACE) VALUES (10, 'VENISE', 1);
INSERT INTO VOYAGE(IDV, DESTINATION, MAXPLACE) VALUES (11, 'PRAGUE', 20);
COMMIT ;
-- Création d'une table temporaire vide de même structure que INSCRIPTION
CREATE GLOBAL TEMPORARY TABLE TEMP_INSCRIPTION AS SELECT * FROM INSCRIPTION WHERE 0=1;
-- 1er déclencheur, de niveau ligne, qui n'interroge plus la table mutante
-- à la place, il stocke dans la table temporaire les données insérées
CREATE OR REPLACE TRIGGER TRIG_INSCRIPTION BEFORE INSERT ON INSCRIPTION FOR EACH ROW
BEGIN
INSERT INTO TEMP_INSCRIPTION(IDC, IDV, DATERESERV) VALUES (:NEW.IDC, :NEW.IDV, :NEW.DATERESERV);
END ;
/
-- second déclencheur, de niveau instruction, qui vérifie qu'il y a des places libres
-- il s'exécute une seule fois, après le traitement de tous les enregistrements touchés par l'INSERT sous-jacent
CREATE OR REPLACE TRIGGER TRIG_INSCRIPTION2 AFTER INSERT ON INSCRIPTION
DECLARE
NB_RESERVE INTEGER ; -- nombre de réservations déjà faites
NB_MAXPLACE INTEGER ; -- nombre de places total
BEGIN
FOR LIGNE IN (SELECT * FROM TEMP_INSCRIPTION ORDER BY DATERESERV) LOOP
SELECT COUNT (*) INTO NB_RESERVE FROM INSCRIPTION
WHERE IDV=LIGNE.IDV;
SELECT MAXPLACE INTO NB_MAXPLACE FROM VOYAGE
WHERE IDV=LIGNE.IDV;
IF NB_MAXPLACE - NB_RESERVE < 0 THEN
Raise_application_error(-20000,'Réservation impossible pour voyage ' || LIGNE.IDV || ' et client ' || LIGNE.IDC);
-- on supprime les inscriptions excédentaires
DELETE FROM INSCRIPTION WHERE IDV=LIGNE.IDV AND IDC=LIGNE.IDC;
END IF ;
END LOOP ;
-- tout à la fin, on remet à zéro la table temporaire. A noter qu'un TRUNCATE n'est pas possible ici, car il débuterait une nouvelle transaction
DELETE FROM TEMP_INSCRIPTION;
END ;
/ |
Partager