Upload
dangkhanh
View
221
Download
0
Embed Size (px)
Citation preview
Les TRIGGERS
Introduction
Triggers ordre
Triggers ligne
Triggers E/C/A
Traitements différenciés
Limitations
Ecriture de triggers vérifiant une contrainte d'intégrité
Gestion des triggers
Application à
9i, 10gORACLE
Schéma d ’une compagnie aérienne
AvionNumavCapaciteTypeEntrepot
PiloteMatriculeNomVilleAgeSalaire
Depart
NumvolDate_depNumavMatricule
PassagerNumabNomab
ReservationNumabNumvolDate_dep
VolNumvolHeure_departHeure_arriveeVille_departVille_arrivee
1) Introduction
Un trigger de type Evénement/Action (EA) est composé d'
un événement qui va le déclencher une action à exécuter au
déclenchement
Les triggers d’Oracle
Un trigger est associé à une table
L'événement qui le déclenche est une opération (insertion, suppression, MAJ) sur cette relation;
L'action à exécuter est spécifiée par un bloc PL/SQL.
Typologie des triggers d’Oracle
TRIGGER
ORDRE LIGNE
BEFORE
AFTER BEFORE AFTER
UPDATEINSERT
DELETE UPDATEINSERT
DELETEUPDATE
INSERT
DELETEUPDATE
INSERT
DELETE
2) Triggers ordre
BEFOREAFTER
CREATE TRIGGER nom_du_triggerBEFORE UPDATE ON nom_de_la_relation
BLOC PL/SQL
UPDATEINSERTDELETEUPDATE OF nom_attribut1, nom_attribut2INSERT OR UPDATE OR DELETE
Le bloc PL/SQL sera exécuté avant chaque instruction"UPDATE nom_de_la_relation"
Gestion des triggers
DROP TRIGGER nom_trigger;
ALTER TRIGGER nom_trigger DISABLE;
ALTER TRIGGER nom_trigger ENABLE;
ALTER TABLE nom_table DISABLE ALL TRIGGERS;
ALTER TABLE nom_table ENABLE ALL TRIGGERS;
Exemple
CREATE TABLE TABLEAU_DE_BORD(date_cumul DATE, nombre_res_vendues INTEGER);INSERT INTO TABLEAU_DE_BORD VALUES (sysdate, 0);
CREATE TRIGGER espionAFTER INSERT ON reservation
DECLAREres INTEGER;
BEGINSELECT MAX (nombre_res_vendues) INTO resFROM TABLEAU_DE_BORD;res := res + 1;INSERT INTO TABLEAU_DE_BORD VALUES (sysdate, res);
END;
Exemple
CREATE TRIGGER grèveBEFORE INSERT OR UPDATE OR DELETE ON reservation
BEGINraise_application_error (-20001, 'Toute réservation est
actuellement impossible');END;
Exercices
Exercice n° 1: Ecrire un trigger qui après chaque suppression d'un pilote annule tous les départs prévus le 25 décembre 2003.
Exercice n° 2: Ecrire un ensemble d'instructions (le programme client) qui permettent de déclencher le trigger ci-dessus.
Correction de l'exercice n° 1
Exercice n° 1: Ecrire un trigger qui après chaque suppression d'un pilote annule tousles départs du 25 décembre 1996.
CREATE OR REPLACE TRIGGER T1AFTER DELETE ON pilote
BEGIN
DELETE FROM departWHERE date_dep = '25-12-2003';
END;
Correction de l'exercice n° 2
Exercice n° 2: Ecrire un ensemble d'instructions (le programme client) qui permettent de déclencher le trigger ci-dessus.
BEGIN
DELETE FROM PiloteWHERE Matricule = 10;
END;
3) Triggers lignes : exemple
CREATE TRIGGER incendieBEFORE INSERT OR UPDATE ON reservationFOR EACH ROW
DECLAREres vol.ville_arrivee%TYPE;
BEGIN
SELECT vol.ville_arrivee INTO resFROM volWHERE vol.numvol = :NEW.numvol;
IF res = 'Bruxelles' THEN raise_application_error (-20001, 'Il est impossible de réserver pour
Bruxelles, l''aéroport étant fermé jusqu''à nouvel ordre');END IF;
END;
Exemple
CREATE TRIGGER Déplacement_zéro/* Le pilote doit habiter dans la ville de départ du vol */BEFORE INSERT OR UPDATE ON DepartFOR EACH ROW
DECLAREville_du_pilote pilote.ville%TYPE;ville_depart_vol vol.ville_depart%TYPE;
BEGINSELECT ville INTO ville_du_piloteFROM piloteWHERE matricule = :NEW.matricule;
SELECT ville_depart INTO ville_depart_volFROM volWHERE numvol = :NEW.numvol;
Exemple (suite)
IF ville_du_pilote != ville_depart_vol THEN raise_application_error (-20789, 'Le pilote ' ||
TO_CHAR (:NEW.matricule)|| 'n''habite pas dans laville de départ du vol' || :NEW.numvol');
END IF;
END;/
> INSERT INTO depart VALUES ('AF 567','31-11-1995',1,23);
ORA-20789: Le pilote 23 n'habite pas dans la ville de départ du vol AF 567.
Exercices
Exercice 3: Ecrire un trigger qui empêche de réserver si le nombre de réservations est déjà égal à la capacité de l'avion.
Exercice 4: Ecrire un bloc client qui déclenche le trigger.4.a - Le bloc ne traite pas les erreurs4.b - Le bloc doit traiter l'erreur éventuelle de surréservation
provoquée par le trigger
Nouveautés dans Oracle 8
A partir d'Oracle 8.0Possibilité de créer des triggers INSTEAD OF sur les vues
A partir d'Oracle 8.1 (Oracle 8i)Possibilité de définir des triggers qui se déclenchent lors de l'exécution d'instructions SQL de type LDD
CREATE, DROP, ALTERPossibilité de définir des triggers qui se déclenchent pour un certain nombre d'événements de la base de données
Démarrage ou arrêt de la baseConnexion, déconnexion d'un utilisateur
Conclusion
Les triggers permettent demaintenir des relations contenant des renseignements sur l'activité de la base,rendre le SGBD "actif", en calculant automatiquement certains attributs, en insérant, modifiant ou supprimant des tuples,contrôler dynamiquement certaines manipulations de la base,contrôler l'intégrité,rafraîchir des données dupliquées.
Compléments
Les triggers ECALes traitements différentiésLimitations des triggersMéthode de mise en place de contrainte d ’application avec les triggers
TRIGGER E/C/A: Définition
Un trigger de type Evénement/Condition/Action (ECA) est composé d'
un événement qui va le déclencher,
une condition à vérifier,
une action à exécuter au déclenchement si la condition est vérifiée.
Définition (suite)
UN TRIGGER E/C/A EST ATTACHE A UNE TABLE
L'événement qui le déclenche est une MISE A JOUR sur cette TABLE;
La condition à vérifier porte sur le TUPLE MIS A JOUR, elle est FACULTATIVE;
L'action à exécuter est spécifiée par un BLOC PL/SQL.
La clause WHEN
CREATE TRIGGER controleBEFORE INSERT ON reservationFOR EACH ROWWHEN (new.numab IN (9,23,567,2993))
BEGIN
IF :NEW.numvol LIKE 'AF%'THEN raise_application_error (-20003, 'Passager
recherché, réservation impossible sur Air France');
END IF;
END;
"WHEN" est associé à "FOR EACH ROW"
"new" n'est pas préfixé de ":" dans la clause WHEN
La clause WHEN (suite)
CREATE TRIGGER controleBEFORE INSERT ON reservationFOR EACH ROW
WHEN (new.numab IN (SELECT numabFROM passagerWHERE nomab IN ('Joe', 'Averell')))
BEGINIF :new.numvol LIKE 'AF%' THEN
raise_application_error (-20003, 'Passagerrecherché, réservation impossiblesur Air France');
END IF;END;
Pas de requête dans la
clause WHEN
Traitements différenciés
CREATE TRIGGER grèveBEFORE INSERT OR UPDATE OR DELETE ON reservation
BEGINIF INSERTING THEN
raise_application_error (-20001,'Toute réservation est actuellementimpossible');
ELSIF UPDATING THENraise_application_error (-20002,
'Il est impossible de modifiervotre réservation');
ELSIF DELETING THENraise_application_error (-20003, 'Inutile
d''annuler, le vol n"a pas lieu'');END IF;
END;
INSERTING, UPDATING et DELETING sont des prédicats utilisables par les instructions conditionnelles de PL/SQL.
Conseils
Un seul triggersur la même TABLE avec les mêmes EVENEMENTS de déclenchementau même moment de déclenchementavec la même granularité (ligne ou ordre)
Exemple : T1 : PILOTE, INSERT, AFTER, FOR EACH ROWT2 : PILOTE, INSERT, AFTER, FOR EACH ROW
Cette limite n’est plus vraie à partirdes dernières versions de Oracle7
Possible à partir d’Oracle8Mais pas conseillé
Limitations (suite)
Pas de SELECT sur une table "MUTANTE"
CREATE TRIGGER T1BEFORE INSERT OR DELETE ON piloteFOR EACH ROW
DECLAREres pilote%ROWTYPE;
BEGINSELECT * INTO res FROM pilote WHERE matricule = 1;
END;
ERROR at line 1:ORA-04091: table SCOTT.PILOTE is mutating,trigger may not see it
> DELETE FROM pilote;
Limitations (suite)
Mais ...
CREATE TRIGGER T1BEFORE INSERT OR DELETE ON piloteFOR EACH ROW
DECLAREres pilote%ROWTYPE;
BEGINSELECT * INTO res FROM pilote WHERE matricule = 1;
END;
> INSERT INTO pilote VALUES (12,'Amandier','Clafoutiville'); OK !
Zone de "SELECT FROM Pilote" interdite(pour CREATE TRIGGER on Pilote)
TRIGGER
ORDRE LIGNE "for each row"
BEFORE AFTER
UPDATEINSERT
DELETEUPDATE
INSERT
DELETEUPDATE
INSERT
DELETE
UPDATEINSERT
DELETE
BEFORE AFTER
Écriture de triggers vérifiant une contrainte d'intégrité
Rappel de définition : Une contrainte d'intégrité est une assertion qui doit toujours être vérifiée par les données de la base.Exemples de contraintes d'intégrité :
C1 : L'âge d'un pilote est supérieur à 18.C2 : Deux pilotes différents ont des matricules différents.C3 : La ville de départ d'un vol est différente de la ville d'arrivée.C4 : La date de réservation n'est pas antérieure à la date du jour.C6 : Un "numab" dans la table "réservation" existe aussi dans la table "passager".C7 : Le nombre de réservations pour un départ ne dépasse pas la capacité de l'avion affecté à ce départ.
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Spécification de la contrainte d'intégrité : Pas de commande unifiée de spécification de contrainte de type CREATE CONSTRAINT (PILOTE.AGE > 18);Mais un ensemble de moyens de spécification :
(1) Dans le "create table"
(1a) Par des mots clésUNIQUENOT NULLFOREIGN KEYPRIMARY KEY
(1b) Contraintes libres monotuples ("check")
(2) Par des triggers
Check (age > 18)Check (ville_arr != ville_dep)Check ( sysdate user )
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Problème : Etant donnée une contrainte d'intégrité, sur quelles tables doit-on spécifier des triggers ?
Exemple du problème :C7 : Le nombre de réservations pour un départ ne dépasse pas la capacité de l'avion affecté à ce départ.Le trigger créé lors de l'exercice précèdent (ex. 3) suffit-il à maintenir la cohérence de la base par rapport à la contrainte C7, quelles que soient les "insert", "update" et "delete" effectués par les utilisateurs sur la base "compagnie aérienne" ?Sur quelles autres tables doit-on spécifier des triggers ?
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Méthode suggérée :
Ecrire la requête qui ramènerait les tuples violant la contrainte d'intégrité,
Spécifier un trigger sur toutes les tables apparaissant dans un "from".
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Exemple d'application de la méthode :
C1 : L'âge d'un pilote est supérieur à 18.
Requête qui ramènerait les tuples violant la contrainte d'intégrité:
Select * from pilote where age < 18.
Il faut un trigger sur PILOTE
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Exemple d'application de la méthode :C7 : Le nombre de réservations pour un départ ne dépasse pas la capacité de l'avion affecté à ce départ.Requête qui ramènerait les tuples violant la contrainte d'intégrité:SELECT *FROM AVIONWHERE Avion.Capacite <
(SELECT COUNT (*)FROM RESERVATION, DEPARTWHERE Avion.numav = Depart.Numav
AND Reservation.numvol = Depart.numvolAND Reservation.date_dep = Depart.date_dep)
Il faut :un trigger sur AVION, un trigger sur DEPART et un trigger sur RESERVATION
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Exemple d'écriture du trigger sur AVION :CREATE TRIGGER T3BEFORE INSERT OR UPDATE ON AVIONFOR EACH ROW
DECLAREremplissage_actuel INTEGER;
BEGINSELECT COUNT (*)INTO remplissage_actuelFROM reservation, départWHERE départ.numav = :new.numavand départ.date_dep = reservation.date_depand départ.numvol = reservation.numvol;
IF :new.numav <= remplissage_actuel THEN raise_application_error
(-20002, 'Avion trop petit; violation de la contrainte C7');
END IF;END;/
Écriture de triggers vérifiant une contrainte d'intégrité (suite)
Exemple d'écriture du trigger sur DEPART :CREATE TRIGGER T2BEFORE INSERT OR UPDATE ON DEPARTFOR EACH ROW
DECLARE
remplissage_actuel INTEGER;capacite_avion INTEGER;
BEGIN
SELECT capacite INTO capacite_avionFROM avionWHERE avion.numav = :new.numav;
...
SELECT COUNT (*)INTO remplissage_actuelFROM reservationWHERE numvol = :NEW.numvolAND date_dep = :NEW.date_dep;
IF capacite_avion <= remplissage_actuel THEN
raise_application_error (-20003,'départ avec surnombre, violation de la contrainte C7');
END IF;END;/