1/18 2/18 Anne-Cécile Caron Licence MIAGE - Bases de Données 2015-2016 Objectifs Après ce cours, les TD et TP correspondants, vous devez être capables de I Ecrire en PL/SQL des triggers liés aux tables. I Utiliser à bon escient le paramétrage des triggers : I I trigger ligne ou instruction trigger before ou after I Dans le cas d un trigger ligne, utiliser correctement new et old I Dans le cas d un trigger ligne, utiliser la clause When I Utiliser les prédicats updating, inserting, deleting I Comprendre donc éviter les erreurs de table en mutation. 3/18 4/18 Définition I Un trigger est un programme qui se déclenche automatiquement suite à un évènement ) A la di érence d une procédure stockée, on ne peut pas appeler un trigger explicitement. I En base de données, l évènement est une instruction du DML qui modifie la base.(insert, DELETE, UPDATE) I Ces triggers font partie du schéma de la base. Leur code compilé est conservé (comme pour les programmes stockés) I Ils font partie de la norme SQL3. I sous Oracle, aussi triggers INSTEAD OF sur les vues, et triggers systèmes Pourquoi? I peuvent servir à vérifier des contraintes que l on ne peut pas définir de façon déclarative I Ils peuvent aussi gérer de la redondance d information. I Ils peuvent aussi servir à collecter des informations sur les mises-à-jour de la base.
5/18 6/18 Syntaxe CREATE [OR REPLACE] TRIGGER <nom_trigger> <instant> <liste_evts> ON <nom_table> [FOR EACH ROW] [WHEN ( <condition> ) ] <corps> <instant> ::= AFTER BEFORE <liste_evts> ::= <evt> {OR <evt>} <evt> ::= DELETE INSERT UPDATE [OF { <liste_cols> }] <liste_col> ::= <nom_col> {, <nom_col> } <corps> corps de pgme PL/SQL Entête du trigger On définit I la table, I les instructions du DML qui déclenchent le trigger I le moment où le trigger va se déclencher par rapport à l instruction DML (avant ou après) I si le trigger se déclenche I une seule fois pour toute l instruction (i.e. trigger instruction), I ou une fois pour chaque ligne modifiée/insérée/supprimée. (i.e. trigger ligne, avec l option FOR EACH ROW) I et éventuellement une condition supplémentaire de déclenchement (clause WHEN) pour les triggers ligne 7/18 8/18 AFTER ou BEFORE? I Si le trigger doit déterminer si l instruction DML est autorisée : utiliser BEFORE I Si le trigger doit fabriquer la valeur d une colonne pour pouvoir ensuite la mettre dans la table : utiliser BEFORE. Par exemple : trigger ligne qui fabrique la valeur de clef primaire à partir d une séquence. I Si on a besoin que l instruction DML soit terminée pour exécuter le corps du trigger : utiliser AFTER I pour des triggers lignes, il se peut que l utilisation de Before ou After n ait aucune importance. Trigger ligne ou instruction? 1. Trigger ligne : - notion de ligne courante, :old désigne la ligne avant modification et :new désigne la ligne après modification. :old :new insert null valeur insérée delete valeur supprimée null update valeur avant modif valeur après modif - et possibilité de limiter le déclenchement par la clause WHEN 2. Trigger instruction : Le trigger est exécuté une fois pour l ensemble de l instruction ) pas de notion de ligne courante.
9/18 10 / 18 Ordre d exécution des triggers Pour une instruction du DML sur une table de la base, il peut y avoir 4 sortes de triggers possibles selon l instant (before, after) et le type (instruction ou ligne). Ces triggers se déclenchent dans l ordre suivant : I Trigger(s) instruction BEFORE I Pour chaque ligne concernée I Trigger(s) ligne BEFORE I Trigger(s) ligne AFTER I Trigger(s) instruction AFTER Clause WHEN On peut définir une condition pour un trigger ligne : le trigger se déclenchera pour chaque ligne vérifiant la condition. Create or replace trigger journal_emp after update of salary on EMPLOYEE when (new.salary < old.salary) insert into EMP_LOG(emp_id, date_evt, msg) values (:new.empno, sysdate, salaire diminué ); Attention syntaxe : dans la clause when il n y a pas de : devant new et old 11 / 18 12 / 18 Clause WHEN (2) Corps du trigger I bloc PL/SQL EMP Empno 9675 5467 2543 salary 3000 1700 2100 4100 Update EMP Set salary = Where salary < 4000 EMP Empno 9675 5467 2543 salary 4100 I prédicat INSERTING (resp. UPDATING, DELETING) qui vaut vrai ssi le trigger a été déclenché par un INSERT (resp UPDATE, DELETE) I pseudo-tuples :new et :old pour les triggers lignes I Il ne faut pas, dans un trigger ligne, interroger une table qui est en cours de modification (problème de table en mutation). 3 lignes modifiées Le trigger se déclenche 2 fois. EMP_LOG Emp_id date_evt msg 03/10/12 Salaire diminué 5467 03/10/12 Salaire diminué
13 / 18 14 / 18 Exemple 1 create or replace trigger clef_auto before insert on T1 when (new.c1 is null) declare la_clef number ; select nvl(max(c1),0)+1 into la_clef from T1 ; :new.c1 := la_clef ; Exemple 1 (suite) create table T1( c1 number(3) constraint t1_pkey primary key, c2 varchar2(20) ); create sequence seq increment by 1 start with 1 ; insert into T1(c2) values ( coucou ) ; create or replace trigger clef_auto before insert on T1 -- ne pas mettre la clause WHEN -- du trigger précédent! select seq.nextval into :new.c1 from dual ; insert into T1(c2) values ( abc ); --> ligne (2, abc ) insert into T1 values (10, def ); --> ligne(10, def ) insert into T1(c2) values ( ghi ); --> ligne(11, ghi ) insert into T1(c2) select c2 from T1bis; ORA-04091: la table CARON.T1 est en mutation ; le déclencheur ou la fonction ne peut la voir... select * from T1; C1 C2 ---------------------------- 1 coucou Remarque : il faut définir un trigger pour empêcher de modifier c1, AFAIREEN EXERCICE 15 / 18 16 / 18 Exemple 2 On reprend l exemple du Commerce, donné aux cours précédents. alter table client add(nbcmdes NUMBER default 0 not null); -- on met à jour Client en fonction des commandes qui existent déjà update client set nbcmdes = (select count(*) from commande where commande.num_client = client.num_client); -- un trigger instruction pour les futures commandes after insert or delete or update of num_client update client set nbcmdes = (select count(*) from commande where commande.num_client = client.num_client); Exemple 2 (suite) I Dans le transparent précédent, le trigger recalcule tous les nbcmdes, même pour des clients pour qui ce nombre n a pas changé. I Si on définit un trigger ligne au lieu d un trigger instruction, on peut ne faire que les calculs nécessaires after insert update client set nbcmdes = nbcmdes+1 where num_client = :new.num_client ; -- faire la meme chose pour delete et update
17 / 18 18 / 18 Exemple 2 (suite et fin) On peut faire 1 seul trigger pour les 3 cas : insert, update, delete. after insert or delete or update of num_client if inserting or updating then update client set nbcmdes = nbcmdes+1 where num_client = :new.num_client ; end if ; if deleting or updating then update client set nbcmdes = nbcmdes-1 where num_client = :old.num_client ; end if ; Synthèse I programmes dont l exécution est déclenchée par les instruction du DML I pratiques pour vérifier des contraintes que l on ne peut pas déclarer dans le schéma. I Ne pas en abuser! I interdépendance entre triggers qui peut être di cile à gérer, cascade de triggers. I coût