Bases de données MySQL Triggers Corrigé Bertrand LIAUDET 1. Les employés triggers Système de triggers B insert EMP - B update EMP - B delete EMP - A insert EMP Update Dept set nbemp++ where ND=new.ND A update EMP Update Dept set nbemp - - where ND=old.ND Update Dept set nbemp++ where ND=new.ND A delete EMP Update Dept set nbemp - - where ND=old.ND B insert DEPT Set nbemp=0 B update DEPT Select count(*) from emp Where nd=new.nd into nb; Set new.nbemp=nb; B delete DEPT - A insert DEPT - A update DEPT - A delete DEPT - Code de triggers Trigger after drop trigger if exists tai_emp; # tai : trigger after insert create trigger tai_emp after insert on emp update dept set nbemp=nbemp+1 where nd=new.nd; insert into emp values (1, "a", "a", "1980-12-31", 0, NULL, 10, 7902);
select * from dept; drop trigger if exists tau_emp; # tai : trigger after update create trigger tau_emp after update on emp update dept set nbemp=nbemp-1 where nd=old.nd; update dept set nbemp=nbemp+1 where nd=new.nd; update emp set nd=20 where ne=1; select * from dept; drop trigger if exists tad_emp; # tai : trigger after delete create trigger tad_emp after delete on emp update dept set nbemp=nbemp-1 where nd=old.nd; delete from emp where ne=1; select * from dept; Trigger before drop trigger if exists tbi_dept; create trigger tbi_dept before insert on dept set new.nbemp = 0; insert into dept values (50, "a", "b", 5); drop trigger if exists tbu_dept; # tbi : trigger before update create trigger tbu_dept before update on dept declare nb int; If old.nbemp!= new.nbemp then select count(*) from emp Where nd=new.nd into nb; set new.nbemp = nb;
update dept set nbemp=1 where nd=50;
1. La bibliothèque - triggers 1) Créer la BD «biblio» à partir du script fourni. 2) On souhaite ajouter l attribut «emprunté» qui est un booléen et précise si un livre est actuellement emprunté ou pas. Passez la requête qui permet d ajouter cet attribut (ALTER TABLE). alter table livres add libre integer; 3) Mettre à jour les valeurs de cet attribut (UPDATE). update livres set libre=1 ; update livres set libre=0 where nl=any(select nl from emprunter where dateret is null); 4) Ecrire les triggers qui permettent de gérer cet attribut calculé. drop trigger if exists tai_emprunter; # tai : trigger after insert create trigger tia_emprunter after insert on emprunter if new.dateret is null then update livres set libre=0 where nl=new.nl; # select new.nl into @vnl; si on veut verifier la valeur de new.nl drop trigger if exists tau_emprunter; # tau : trigger after update create trigger tau_emprunter after update on emprunter if new.dateret is not null then update livres set libre=1 where nl=new.nl; # select new.nl into @vnl; pour verifier la valeur de new.nl REMARQUE : L attribut devrait aussi être géré dans la table des livres : à la création et en modification. Au minimum, on a intérêt à définir une valeur par défaut à la création : alter table livres modify libre integer default 1 ; 5) On souhaite ajouter l attribut «dureeemprunt» qui donne la durée de l emprunt en jours après le retour du livre. Ecrire la requête qui permet d ajouter cet attribut (ALTER TABLE). alter table emprunter add dureeemprunt integer;
6) Mettre à jour les valeurs de cet attribut pour tous les tuples de la table concernée (UPDATE). update emprunter set dureeemprunt = to_days(dateret)-to_days(dateemp) where dateret is not null; 7) Ecrire le système de triggers qui permet de gérer cet attribut calculé. drop trigger if exists tbi_emprunter; create trigger tbi_emprunter before insert on emprunter set new.dureeemprunt = to_days(new.dateret)-to_days(new.dateemp); drop trigger if exists tbu_emprunter; # tbu : trigger before update create trigger tbu_emprunter before update on emprunter set new.dureeemprunt = to_days(new.dateret)-to_days(new.dateemp); remarques : On peut se contenter de réaffecter («setter») dureeemprunt dans tous les cas. Si l une des deux dates vaut NULL, dureeemprunt vaudra NULL. 8) On souhaite que la date d emprunt soit désormais un attribut automatique qui vaut automatiquement la date du jour de la création du tuple correspondant dans la BD. Comment faire ça? Ecrire le code correspondant. Solution 1 : attribut timestamp alter table emprunter modify dureemax integer not null default 14; alter table emprunter modify dateemp timestamp default now(); remarques : Un attribut de type timestamp est affecté automatiquement aux date et heure de création et de modification. Il est not null par défaut. Si on ajoute default now() : il prendra les date et heure de création mais ne sera pas modifié en cas de modification. Par contre si on remet la valeur de dateemp à NULL, dateemp prend la valeur des date et heure de modification. Si on affecte une valeur à dateemp, elle est prise en compte. Solution 1 : gestion d un trigger beefore drop trigger if exists tbi_emprunter; # tai : trigger after insert create trigger tbi_emprunter before insert on emprunter
set new.dateemp=current_date(); drop trigger if exists tbu_emprunter; # tau : trigger after update create trigger tbu_emprunter before update on emprunter if new.dateemp!= old.dateemp then set new.dateemp= old.dateemp; 9) On souhaite que les noms de famille soient en majuscules et les prénom en minuscules avec seulement la première lettre en majuscule. Ecrire le système de triggers qui permet de gérer cette demande. drop trigger if exists tbi_adherents; create trigger tbi_adherents before insert on adherents set new.nom=upper(new.nom); set new.prenom=concat(upper(substr(new.prenom,1,1)), lower(substr(new.prenom,2,length(new.prenom)-1))); drop trigger if exists tbu_adherents; # tbi : trigger before update create trigger tbu_adherents before update on adherents if old.nom!= new.nom then set new.nom=upper(new.nom); if old.prenom!= new.prenom then set new.prenom=concat(upper(substr(new.prenom,1,1)), lower(substr(new.prenom,2,length(new.prenom)-1))); 10) On souhaite interdire l emprunt d un livre déjà emprunté. Ecrire le trigger. drop trigger if exists tbi_emprunter; create trigger tbi_emprunter before insert on emprunter declare meserr integer;
declare vnl integer; set vnl = null; select nl into vnl from emprunter where nl=new.nl and dateret is null; if vnl is not null then select le livre est déjà emprunté into @messerr; select le livre est déjà emprunté into meserr from livres; # else # update livres set libre=0 where nl=new.nl ; # inutile avec le trigger after 11) On souhaite interdire l emprunt de plus de 3 livres par le même adhérent. Ecrire le trigger. drop trigger if exists tbi_emprunter; create trigger tbi_emprunter before insert on emprunter declare vnl integer; declare vnbemp integer; set vnl = null; select nl into vnl from emprunter where nl=new.nl and dateret is null; if vnl is not null then select le livre est déjà emprunté into @messerr; select 1,2 into vnl; else select count(*) into vnbemp from emprunter where na=new.na ; if vnbemp = 3 then select concat( l\ adherent, new.na, a déjà emprunté 3 livres ) into @messerr; select 1,2 into vnl; set new.dureeemprunt = to_days(new.dateret)-to_days(new.dateemp); 12) On souhaite que la date de retour prenne automatiquement la valeur de la date du jour du rendu du livre. On souhaite interdire un rendu le jour même de l emprunt et que la date de retour soit postérieur à la date d emprunt. On souhaite interdire toute modification du tuple. Ecrire le trigger. drop trigger if exists tbu_emprunter; # tbu : trigger before update create trigger tbu_emprunter before update on emprunter declare vnb integer; if old.dateret is not null or (old.dateret is null and (old.nl!=new.nl or old.na!=new.na or old.dureemax!=new.dureemax) ) then select un emprunt ne peut pas être modifié into @messerr; select 1,2 into vnb; if current_date() = new.dateemp then
select un emprunt ne peut être rendu le jour de l emprunt into @messerr; select 1,2 into vnb; if new.dateret!= current_date then select la date de retour doit être celle du jour into @messerr; select 1,2 into vnb; set new.dureeemprunt = to_days(new.dateret)-to_days(new.dateemp); 13) Après analyse, on décide de fusionner les tables LIVRES et OEUVRES en une seule table : écrire le script de requêtes permettant de faire cette modification. Alter table livres add titre varchar(150), add auteur varchar(100); drop procedure if exists exo9; create procedure exo9() declare i, vno int; declare vauteur varchar(100); declare vtitre varchar(150); declare vide int; declare curseur cursor for select no, titre, auteur from oeuvres; declare continue handler for not found set vide = 1 ; -- attention: si on met 0 ça boucle sans fin!!! set i=1; set vide=0; open curseur; maboucle: loop fetch curseur into vno, vtitre, vauteur; if vide=1 then leave maboucle; update livres set titre=vtitre, auteur=vauteur where no=vno; set i=i+1; end loop; close curseur; end ; call exo9(); select * from livres; 14) Ecrire le ou les triggers qui vérifient la cohérence des données suite à cette modification. drop trigger if exists tbi_livres; create trigger tbi_livres before insert on livres declare meserr integer; declare vnb int; declare vauteur varchar(100); declare vtitre varchar(150); select count(*) into vnb from livres where no=new.no; set @vnbout=vnb;
if vnb!= 0 then select titre, auteur into vtitre, vauteur from livres where no=new.no limit 1; if vauteur!= new.auteur or vtitre!= new.titre then select oeuvre incohérente into @messerr; select oeuvre incohérente into meserr from livres; else insert into oeuvres values (new.no, new.auteur, new.titre); drop trigger if exists tbu_livres; # tbu : trigger before update create trigger tbu_livres before update on livres declare meserr integer; declare vnb int; declare vauteur varchar(100); declare vtitre varchar(150); # si on a saisi une nouvelle valeur pour NO if old.no!= new.no then select count(*) into vnb from livres where no=new.no; set @vnbout=vnb; # si la valeur saisie pour NO est déjà dans livres if vnb!= 0 then # on récupère le titre et l auteur du NO saisi select titre, auteur into vtitre, vauteur from livres where no=new.no limit 1; # si on n a pas change le titre et l auteur, # on passe au nouveau titre, nouvel auteur if old.auteur=new.auteur and old.titre=new.titre then set new.auteur=vauteur; set new.titre=vtitre ; # si on a changé le titre ou l auteur et que c est différent # de celui du NO, c est incohérent if vauteur!= new.auteur or vtitre!= new.titre then select oeuvre incohérente into @messerr; select oeuvre incohérente into meserr from livres; # si la valeur saisie pour NO n est pas dans livres else insert into oeuvres values (new.no, new.auteur, new.titre); # si on n a pas saisi de nouvelle valeur pour NO elseif old.auteur!=new.auteur or old.titre!=new.titre then select oeuvre incohérente into @messerr; select oeuvre incohérente into meserr from livres;