Вы находитесь на странице: 1из 83

L2A

Semestre 4
Mehdi Benzine
Introduction
 SQL est un langage déclaratif non procédural

 Certains traitements complexes nécessitent


l'utilisation d'un langage procédural permettant la
manipulation de variables et de structures de contrôle
telles que les conditions et les boucles.

 Il est parfois nécessaire d'effectuer des traitements


complexes sur le résultat d'une requête SQL de le
formater d'une certaine particulière.
2
PL/SQL
 PL/SQL (Procedural Language/ Structured Query Language) est
un langage impératif procédural propre aux SGBDR Oracle.

 La plupart des SGBDR disposent de leur langage impératif


procédural (SQL Server, PostgreSQL …)

 PL/SQL permet de définir des blocs d'instructions anonymes,


des procédures et des fonctions.

 Un bloc PL/SQL peut être utilisé pour définir un Trigger


(déclencheur).

 Il est possible à partir d'un programme PL/SQL d'exécuter des


instructions SQL.
3
Utilisations de PL/SQL
 PL/SQL est utilisé pour définir des procédures stockées
pouvant être appelée par la suite.

 PL/SQL permet d'écrire des fonctions utilisables par les


requêtes SQL.

 PL/SQL permet d'écrire des triggers (procédures


déclenchées par la modification de données)

 PL/SQL permet de regrouper ensemble des fonctions et des


procédures dans des paquetages pour constituer des
bibliothèques réutilisables.

4
Blocs PL/SQL
Le langage PL/SQL permet de définir 3 types de blocs:

1. Blocs anonymes: bloc composé d'une ensemble de


déclarations de variables et d'instructions à exécuter.

2. Procédures stockées: procédure définie et stockée par le


SGBDR, pouvant être appelée dans n'importe quel bloc
PL/SQL.

3. Fonctions stockées: fonction définie et stockée par le


SGBDR, pouvant être utilisée dans n'importe quel bloc
PL/SQL ou requête SQL.

5
Structure d'un bloc PL/SQL
Un bloc peut contenir les sections suivantes:
[DECLARE
--Déclaration de variables et de constantes
]
BEGIN
-- Séquence d'instructions
[EXCEPTION
-- Gestion des exceptions (division par zéro, …)
]
END;
/

Les sections déclaration de variables et gestion des exceptions sont facultatives.


Les commentaires sur plusieurs lignes sont encadré par '/*' et '*/' .
Les commentaires sur une ligne commencent par '--'.

6
Identifiant
 Comme SQL, PL/SQL est insensible à la casse. Il ne
fait pas la différence entre majuscules et minuscules
dans le traitement des mots clé et des identifiants.

 Un identifiant doit avoir une taille maximum de 30


caractères et contenir tous les caractères
alphanumériques en plus des caractères '#', '$', '_'. Un
identifiant doit obligatoirement commencer par une
lettre.
7
Zone DECLARE
La zone DECLARE permet de déclarer et d'initialiser les variables et les
constantes qui seront utilisées par la suite.

Déclaration de constante:
nom_cons CONSTANT type := valeur;

Déclaration de variable:
nom_var type [[NOT NULL] := valeur];

Exemple:

DECLARE
nom VARCHAR2(60);
age NUMBER(3) NOT NULL := 18;
tva CONSTANT NUMBER(0,2) := 0.17;

8
Types de variables
 Tous les types de données Oracle sont présents dans PL/SQL

 Le type BOOLEAN existe en PL/SQL


test BOOLEAN := true;

 Il est possible d'associer à une variable le type d'une variable existante, de


la colonne d'une table ou d'une vue.
v_prenom Employé.Prénom%TYPE;

 Une variable peut contenir tous les attributs d'une table.


v_emp Employé%ROWTYPE
v_emp est déclarée comme une variable pouvant stocker une ligne de la
table Employé.
v_emp.NumEmployé, v_emp.Nom, v_emp.Prénom,
v_emp.Date_Naissance, v_emp.Fonction, v_emp.Est_cadre.

9
Variables
Une variable peut:
1. être initialisée au moment de sa déclaration
var type := valeur;
v_salaire NUMBER (7,2) := 42000;

2. se voir affecter une valeur


var := valeur;
v_prenom := 'Fateh';

3. recevoir une valeur provenant d'une requête SQL


SELECT col1 [, col2, …, coln] INTO var1 [, var2, …, varn]
FROM table

La requête doit obligatoirement renvoyer un seul tuple!!!!
SELECT Date_Naissance INTO v_date_nais
FROM Employé
WHERE Num_Employé = 1009;

10
Exemple 1
DECLARE
v_emp Employé%ROWTYPE;

BEGIN

SELECT * INTO v_emp


FROM Employé
WHERE Num_Employé = 1009;

dbms_output.put_line('Nom: ' || v_emp.Nom || ' Prénom: ' || v_emp.Prénom);


END;
/
La fonction put_line du package dbms_output permet d'afficher une chaine de
caractères (équivalent de printf en C).

11
RECORD
RECORD permet de définir un nouveau type composé de
champs élémentaires. (équivalent aux structures C)

TYPE nom IS RECORD(


Champs1 type,
Champs2 type,
…);

12
RECORD
TYPE etat_civil IS RECORD(
Nom Employé.Nom%TYPE,
Prénom Employé.Prénom%TYPE,
Date_Naissance Employé.Date_Naissance%TYPE);

v_personne etat_civil;
v_personne.Nom := 'Kermi';
v_personne.Prénom := 'Youcef';
v_personne.Date_Naissance := '19/08/1983';
13
Condition (IF THEN ELSE)
IF condition THEN DECLARE
Bloc d'instructions 1 v_emp Employé%ROWTYPE;
[ELSE BEGIN
SELECT * INTO v_emp
Bloc d'instructions
2] FROM Employé
WHERE Num_Employé = 1009;
END IF;
IF v_emp.Date_Naissance < '18/04/1947' THEN
INSERT INTO Retraité
VALUES(v_emp.Num_Employé, v_emp.Nom,
v_emp.Prénom, v_emp.Date_Naissance,
v_emp.Fonction, v_emp.Est_Cadre)
END IF;

14
Condition (IF THEN ELSEIF)
IF condition THEN
Bloc d'instructions 1
[ELSEIF
Bloc d'instructions 2]

[ELSE
Bloc d'instructions n]

END IF;
15
Choix
CASE expression
WHEN expression1 THEN Bloc1;
[WHEN expression2 THEN Bloc2;]

[ELSE Bloc n;]
END CASE;

Expression équivalente au switch en C


Expression doit correspondre à un type atomique.
16
Boucles WHILE
WHILE condition LOOP
Bloc d'instructions
END LOOP;

WHILE i < 10 LOOP


i := i + 1;
END LOOP;

17
Boucles LOOP
LOOP
Bloc d'instructions 1
[EXIT WHEN condition]
Bloc d'instructions 2
END LOOP;

LOOP
i = i + 1;
EXIT WHEN i >= 10;
END LOOP; 18
Boucles FOR
FOR cpt IN [REVERSE] i TO j LOOP
Bloc d'instructions
END LOOP;
Si REVERSE n'est pas utilisé i < j, sinon i > j

FOR i IN 0 TO 10 LOOP FOR i IN REVERSE 10 TO 0 LOOP


… …
END LOOP; END LOOP;

19
Curseurs (1)
Un curseur est une zone mémoire temporaire utilisée au
moment de l'exécution d'une requête SQL. Un curseur
contient les informations relatives à la requête SQL
exécutée et aux lignes sélectionnées par cette requête.

20
Curseurs (2)
Il existe deux types de curseurs:

Les curseurs implicites: créé automatiquement lors de l'exécution


d'une requête INSERT, UPDATE, DELETE ou d'une requête
SELECT…INTO ne retournant qu'un seul tuple.

Les curseurs explicites: créé par le développeur PL/SQL lors de


l'exécution d'une requête SELECT… INTO qui retourne plus d'un
tuple. Bien que contenant tous les tuples résultats d'une requête,
les tuples ne peuvent être accédés qu'un seul à la fois. Le tuple
accédé est appelé le tuple courant. Le curseur dispose d'un pointeur
qui référence le tuple courant. L'accès à un tuple fait passé le
pointeur au tuple suivant. Il est ainsi possible de consulter tous les
tuples résultat du premier au dernier en se déplaçant à chaque fois
d'un tuple dans le résultat.
21
Curseur implicite
 Curseur généré automatiquement lors de l'exécution d'une requête
INSRET, UPDATE, DELETE ou SELECT… INTO retournant un seul
tuple.

 Le curseur implicite est nommé SQL.

 Lors de l'exécution d'une requête INSERT, UPDATE ou DELETE


PL/SQL offre un ensemble d'attributs pour obtenir des informations
sur les tuples affectés par la requête (nombre de tuples …).

 Lors de l'exécution d'une requête SELECT…INTO retournant


théoriquement un seul tuple, PL/SQL offre des attributs permettant de
savoir si un tuple a été retourné. PL/SQL génère une erreur si aucun
tuple n'est retourné.

22
Curseur implicite
Les attributs du curseur implicite sont:
 %FOUND
 %NOTFOUND
 %ROWCOUNT
 %ISOPEN

SQL%FOUND contient la valeur true si la requête INSERT, UPDATE ou DELETE exécuté a affecté au
moins un tuple. Il contient true également si la requête SELECT… INTO ayant généré le curseur a renvoyé
au moins un tuple. Cet attribut contient la valeur false si aucun tuple n'est affectée par l'instruction
INSERT, UPDATE ou DELETE et il contient false également si aucun tuple n'est retourné par la requête
SELECT…INTO.

SQL%NOTFOUND contient l'inverse de SQL%FOUND.

SQL%ROWCOUNT contient le nombre de tuples affectés par la requête INSERT, UPDATE ou DELETE,
ainsi que le nombre de tuples renvoyés par la requête SELECT …INTO.

SQL%ISOPEN booléen indiquant si le curseur est ouvert. Contient toujours la valeur false. Un curseur
implicite est ouvert au moment de l'exécution de la requête et refermé tout de suite après.

23
Curseur implicite
v_emp Employé%ROWTYPE;

SELECT * INTO v_emp
FROM Employé
WHERE Num_Employé = 1009;
--Un tuple est retourné par cette requête
SQL%FOUND contient true
SQL%NOTFOUND contient false
SQL%ROWCOUNT contient 1
24
Exemple
DECLARE
nb_tuples
BEGIN
DELETE FROM Employé WHERE Num_Employé = 1009;
nb_tuples := SQL%ROWCOUNT;
IF nb_tuples = 0 THEN
dbms_output.putline('Aucun tuple supprimé');
ELSEIF nb_tuple = 1 THEN
dbms_output.putline('1 tuple supprimé');
ELSE
dbms_output.put_line(nb_tuples || ' supprimés (contrainte
d''entité violée)');
END IF;
END;
25
Curseur explicite
 Curseur utilisé pour traiter les requêtes SELECT…INTO
renvoyant plusieurs tuples.

 Déclaré dans la zone DECLARE du bloc.

CURSOR nom_curseur IS SELECT …

Exemple:

DECLARE
CURSOR projets IS SELECT Description, Budget FROM Projet;
26
Curseur explicite
Il y a 4 étapes dans la manipulation d'un curseur
explicite:

1. Déclaration: dans la zone DECLARE


2. Ouverture du curseur: utilisation de OPEN
3. Transfert de données dans des variables (ou RECORD)
PL/SQL: utilisation de FETCH
4. Fermeture du curseur: utilisation de CLOSE

27
Utilisation du curseur
 Une fois qu'un curseur explicite est déclaré, il est
possible de l'utiliser dans la zone d'exécution du bloc.

 L'utilisation du curseur passe par 3 étapes:


1. Ouvrir le curseur
2. Lire les tuples du curseur un par un
3. Fermer le curseur

28
Ouvrir un curseur
OPEN nom_curseur;

Cette opération va consister à exécuter la requête


associée au curseur.

Exemple:
DECLARE

BEGIN
OPEN projets;
29
Lecture des tuples
FETCH nom_curseur INTO var1[, var2, …];
Ou
FETCH nom_curseur INTO record;

Cette opération va copier les valeurs des colonnes du


tuple courant dans les variables correspondantes ou dans
les champs du RCORD.

Après chaque FETCH, un pointeur de position se déplace


vers le tuple suivant faisant de lui le tuple courant.

30
Lecture de tuples
DECLARE
v_description Projet.Description%TYPE;
v_budget Projet.Budget%TYPE;
CURSOR projets IS SELECT Decription, Budget FROM
Projet;
BEGIN
OPEN projets;
FETCH projets INTO v_description, v_budget;
Les variables doivent être placées dans le même ordre que les
attributs correspondants du curseur. Les variables doivent
avoir des types compatibles avec les attributs correspondants.

31
Tuple courant
 Quand un curseur est ouvert, le premier tuple du résultat devient le
tuple courant.

 Le premier FETCH retourne ce tuple courant et déplace le pointeur de


position vers le deuxième tuple qui devient le tuple courant.

 Après chaque FETCH le pointeur se déplace vers le tuple suivant.

 Après avoir lu tout les tuples le dernier FETCH ne retourne plus rien.

 Pour savoir si un FETCH à retourner un tuple ou non, il faut tester


l'attribut %FOUND ou %NOTFOUND du curseur.

 L'attribut %ROWCOUNT permet de savoir combien de tuples ont déjà


été retourné par FETCH.
32
Lecture de tuples
DECLARE
TYPE Desc_bu IS RECORD(
description Projet.Description%TYPE,
budget Projet.Budget%TYPE);
tpl Desc_bu;
CURSOR projets IS SELECT Decription, Budget FROM
Projet;
BEGIN
OPEN projets;
FETCH projets INTO tpl;
Le RECORD doit avoir le même schéma que le curseur
(même nombre de champs et types compatibles)
33
Fermeture du curseur
Après avoir utilisé un curseur explicite il est nécesaire de
le fermer.

CLOSE nom_curseur;

Exemple:
CLOSE projets;

34
Attributs du curseur explicite
Le curseur explicite dispose des attributs suivants:
 %FOUND
 %NOTFOUND
 %ROWCOUNT
 %ISOPEN

 Les 2 premiers ont la même signification que pour les curseurs


implicites.

 %ROWCOUNT indique le nombre de tuples déjà lus à partir du


résultat de la requête SELECT ou le nombre de tuples affectés par une
instruction INSERT, UPDATE ou DELETE.

 %ISOPEN retourne true si le curseur est ouvert. False dans le cas


contraire.

35
Parcourir un curseur (1)
Il est possible d'utiliser une boucle pour parcourir un curseur.
DECLARE

BEGIN
OPEN projets;
LOOP
FETCH projets INTO description_v, budget_v;
EXIT WHEN projets%NOTFOUND;
dbms_output.put_line('Decription: ' || v_desription
|| ' Budget: ' || v_budget);
END LOOP;
CLOSE projets;
END;
36
Parcourir un curseur (2)
DECLARE

BEGIN
OPEN projets;
FETCH projets INTO v_description, v_budget;
WHILE projets%FOUND THEN
LOOP
dbms_output.put_line('Decription: ' ||
v_desription || ' Budget: ' || v_budget);
FETCH projets INTO v_description, v_budget;
END LOOP;
CLOSE projets;
END;
37
Parcourir un curseur (3)
DECLARE

BEGIN
FOR tpl IN projets LOOP
dbms_output.putline('Decription: ' ||
tpl.desription || ' Budget: ' || tpl.budget);
END LOOP;
END;

Les opérations d'ouverture, parcours et fermeture du curseur se


font automatiquement.
38
Procédure stockée
 Une procédure stockée (ou procédure) est un bloc PL/SQL
permettant de réaliser un certains nombre d'instructions.

 Une procédure à un prototype et un corps.


 Le prototype est constitué du nom de la procédure et d'un
ensemble de paramètres.
 Le corps est un bloc PL/SQL.

 Une procédure stockées peut être appelée par n'importe


quel bloc PL/SQL.

39
Paramètres
Il faut distinguer trois types de paramètres:

 Paramètres IN: utilisé pour passer une valeur du bloc qui a


fait l'appel à la procédure.

 Paramètres OUT: utilisé pour passer une valeur de la


procédure au bloc qui l'a appelée.

 Paramètres IN OUT: utilisé pour passer une valeur à la


procédure et pour retournée une valeur au bloc appelant.

40
Procédure stockée
CREATE [OR REPLACE] PROCEDURE nom [paramètres]
IS
DECLARE

BEGIN

END;

REPLACE: permet, dans le cas où la procédure existe déjà, de


la remplacer.
41
Exemple
CREATE OR REPLACE PROCEDURE affiche_budget(v_projet_num IN
Projet.Num_Projet%TYPE)
IS
v_budget Projet.Budget%TYPE;
BEGIN
SELECT Budget INTO v_budget FROM Projet WHERE Num_Projet =
v_projet_num;
dbms_output.putline('Le budget du projet ' || v_projet_num || ' est de '
|| v_budget);
END;

42
Procédure
Pour tester cette procédure il suffit de taper dans Oracle
SQL developer:
EXECUTE affiche_budget(122);

Ou dans un bloc PL/SQL en ajoutant une instruction:

Affiche_budget(122);

43
Fonction
Les fonctions PL/SQL sont des procédures stockées
ayant une valeur de retour.

Les fonctions peuvent être appelées dans des blocs


PL/SQL ou dans des requêtes SQL.

44
Fonction
CREATE [OR REPLACE] FUNCTION nom [paramètres]
RETURN type_retour
IS
/* Déclaration de variables*/
var1 type;
var2 type;

BEGIN

return var1;
EXCEPTION

return var2;
END;

45
Exemple
CREATE OR REPLACE FUNCTION fn_budget (v_projet_num IN
Projet.Num_Projet%TYPE)
RETURN Projet.Budget%TYPE
IS
v_budget Projet.Budget%TYPE;
BEGIN
SELECT Budget INTO v_budget FROM Projet WHERE
Num_Projet = v_projet_num;
return v_budget;
END;

46
Fonction
Pour tester cette fonction, il suffit de taper dans Oracle
SQL Developer:

SELECT fn_budget(108)
FROM DUAL;

Ou dans un bloc PL/SQL:


var := fn_budget(108);

47
Exception
 PL/SQL permet la gestion des exceptions
 PL/SQL dispose d'exceptions prédéfinies
 Il est possible au développeur de définir de nouvelles
exceptions
 Lorsqu'une exception survient, un traitement adapté doit
être exécuté et/ou un message d'exception affiché à
l'utilisateur
 Chaque message d'exception dispose
 d'un type d'exception
 d'un code erreur
 et d'un message à afficher

48
Gestion des exceptions
DECLARE

BEGIN

EXCEPTION
WHEN exception1 THEN
gestion exception1
WHEN exception2 THEN
gestion exception2

END;

49
Types d'exceptions prédéfinies
 CURSOR_ALREADY_OPEN: se produit quand on essaye
d'ouvrir un curseur déjà ouvert.

 NO_DATA_FOUND: se produit quand une requête SELECT


… INTO ne retourne aucun tuple.

 ZERO_DIVIDE: se produit lorsque on essaye de diviser un


nombre par 0.
 TOO_MANY_ROWS: se produit lorsque on place dans un
record ou une variable plus d'un tuple à la fois.
…

50
Lever une erreur
 La fonction PL/SQL RAISE_APPLICATION_ERROR
permet au développeur de lever une erreur s'il constate
une anomalie dans l'exécution d'un bloc PL/SQL.

 RAISE_APPLICATION_ERROR prend en paramètres:


 Un code erreur compris entre -20000 et -20999
 Un message d'erreur

51
Lever une erreur
DECLARE

budget_faible EXCEPTION;
BEGIN
FOR tpl IN projets
LOOP
IF tpl.budget< 15000 THEN
RAISE budget_faible;
END IF;
END LOOP;
EXCEPTION
WHEN budget_faible THEN
RAISE_APPLICATION_ERROR(-20000, 'Budget trop faible');
END;

52
Packages
Oracle met à la disposition des développeurs un
ensemble d'objets (procédures, de fonctions, de type, de
constantes…) prédéfinies et regroupées dans des
packages.

Il est également possible de créer soit même ses propres


packages PL/SQL regroupant ses propres objets PL/SQL.

Exemple:
La procédure dbms_putline du package dbms_output.

53
Séparateur
Dans un script comprenant plusieurs blocs PL/SQL
et/ou instructions SQL indépendants, il est nécessaire
de terminer chaque bloc PL/SQL par un '/'.

CREATE OR REPLACE FUNCTION F1



END;
/
CREATE OR REPLACE PROCEDURE P1

END;

54
55
Introduction
Un trigger (déclencheur) est une procédure stockée qui
s'exécute lorsque survient un évènement prédéfini [et si
une condition est vérifiée].

Une action
Un évènement
Une condition

56
Evènement
Sur Oracle un l'évènement peut être un évènement système:
 Démarrage du SGBD (STARTUP)
 Arrêt du SGBD (SHUTDOWN)
 Erreur interne du SGBD (SERVERERROR)
 Connexion d'un utilisateur LOGON
 …
ou une instruction DML de mise à jour:
 INSERT
 UPDATE
 DELETE
Ou une instruction DDL:
 CREATE
 ALTER
 DROP

57
Utilisation des Triggers
Les Triggers peuvent être utilisés pour:
 des tâches d'administration du SGBD
 des tâches de journalisation des évènements
 l'automatisation de certaines actions
 appliquer des contraintes d'intégrité ne pouvant être
exprimées de manière déclarative
…

Dans ce cours nous ne nous intéresserons qu'à l'application


de contraintes d'intégrité grâce aux Triggers(et
l'automatisation des mises à jour en cascade).

58
Contraintes d'intégrité
Certaines contraintes d'intégrités ne peuvent être exprimées
de manière déclarative lors de la définition d'une table.

Contraintes impliquant plusieurs tuples


Contraintes impliquant des tuples de plusieurs tables
Contraintes temporelles
…
Exemples:
La période d'affectation d'un employé à un projet doit
correspondre à la période d'affectation de son supérieur
La période d'affectation d'un employé à un projet doit être
comprise entre la date de début et la date de fin du projet
Le salaire d'un employé ne peut diminuer

59
Triggers sous Oracle
Pour vérifier ces contraintes d'intégrité, il est possible
d'utiliser des Triggers (déclencheurs).

Un Trigger est une procédure stockée PL/SQL associée à une


vue ou une table. Le Trigger déclenchée par un évènement et
doit réaliser une action (bloc d'instructions PL/SQL).

Les types d'évènements pouvant déclencher un trigger sont:


une instruction d'insertion dans une table
une instruction de suppression dans un table
une instruction de mise à jour d'un ou plusieurs attributs dans
un table

60
Schéma Exemple
Projet (Num_Projet, Description, Date_Début, Date_Fin, Budget)

Employé (Num_Employé, Nom, Prénom, Date_Naissance, Fonction,


Salaire)

Affectation (Num_Employé, Num_Projet, Debut_Affect, Fin_Affect,


Supérieur)

Retraité (Num_Employé, Nom, Prénom, Date_Naissance, Fonction,


Salaire)

61
Relation Employé

Num_Employé Nom Prénom Date_Naissance Fonction Salaire


1001 Belaid Toufik 12/05/1965 Concepteur 37000
1009 Touati Rachid 13/09/1941 Chef de projet 58000
1023 Kadri Amine 23/11/1970 Développeur 29000
1053 Djabi Fatiha 04/06/1980 Analyste 21500
1026 Bouras Kamel 19/04/1968 Administrateur 36000
1005 Djabi Fatiha 22/08/1976 Développeur 32750

62
Déclaration de Trigger
Un trigger peut être exécuté avant (BEFORE) ou après (AFTER) l'évènement
déclencheur.

CREATE [OR REPLACE] TRIGGER nom_trigger


BEFORE|AFTER INSRET OR DELETE OR UPDATE ON nom_table

CREATE TRIGGER nom_trigger


BEFORE|AFTER INSERT OR DELETE OR UPDATE ON nom_table

CREATE TRIGGER insert_employe


AFTER INSERT ON Employé

CREATE TRIGGER modif_projet


AFTER DELETE OR UPDATE ON Projet

63
Déclaration de Trigger
Pour l'évènement déclencheur UPDATE, il est possible
de spécifier la liste des attributs devant être modifiés
pour déclencher le Trigger. Si aucun n'est spécifié,
n'importe quel attribut modifié déclenchera le Trigger.

Exemple:
CREATE TRIGGER modif_projet
AFTER UPDATE OF Date_Début, Date_Fin, Budget ON Projet

64
Types de Triggers
Il existe sous Oracle deux types de Triggers:
 Triggers exécutés une seule fois par instruction (Trigger
instruction, Trigger statement)
 Triggers exécutés une fois par tuple affecté (Trigger ligne,
Trigger row)

Pour le premier type, si un Trigger est déclenché par la


modification de plusieurs tuples, il ne sera exécuté qu'une
seule fois.

Pour le second type, si un Trigger est déclenché par une


modification concernant plusieurs tuples, il sera déclenché
une fois pour chaque tuple modifié.

65
Types de Triggers
Exemple 1:
Un Trigger devant vérifier que la somme de tous les salaires des
employés doit rester inférieure à 1000000.00DA ne doit se
déclencher qu'une seule fois même plusieurs salaires sont modifiés
par une instruction de mise à jour.

UPDATE Employé
SET Salaire = Salaire + variation_salaire (Num_Employé)
Requête impactant 6 tuples.
Trigger exécuté une seule fois.

variation_salaire(number) doit avoir été définie comme fonction


calculant l'augmentation à accorder à l'employé dont le numéro est
passé en paramètre.
66
Relation Employé

Num_Employé Nom Prénom Date_Naissance Fonction Salaire


1001 Belaid Toufik 12/05/1965 Concepteur 37000
1009 Touati Rachid 13/09/1941 Chef de projet 58000
1023 Kadri Amine 23/11/1970 Développeur 29000
1053 Djabi Fatiha 04/06/1980 Analyste 21500
1026 Bouras Kamel 19/04/1968 Administrateur 36000
1005 Djabi Fatiha 22/08/1976 Développeur 32750

67
Types de Triggers
Exemple 2:
Un Trigger devant vérifier que chaque salaire a augmenté
et non pas diminué doit être déclenché pour chaque
tuple impacté par la mise à jour

UPDATE Employé
SET Salaire = Salaire + variation_salaire (Num_Employé)
Requête impactant 6 tuples.
Trigger exécuté 6 fois.

68
Type de Triggers
Par défaut, un Trigger ne s'exécute qu'une fois si l'évènement
déclencheur survient.

Pour exprimé le fait qu'un Trigger s'applique à chaque tuple


impacté par une modification il faut ajouter la clause FOR
EACH ROW.

Exemple:
CREATE TRIGGER modif_employe
AFTER UPDATE Salaire ON Employé
FOR EACH ROW

69
Trigger ligne
Il est possible, pour les Triggers ligne, d'effectuer une sélection sur
les tuples à traiter grâce à une expression logique SQL. Cette
expression logique ne peut pas comporter de sous-requête.

La clause WHEN est utilisée pour introduire cette requête.

CREATE TRIGGER modif_salaire


AFTER UPDATE Salaire ON Employé
FOR EACH ROW
WHEN (Fonction = 'Concepteur' OR Fonction = 'Chef de projet')
...
Empêchera l'exécution du Trigger pour les employés dont la
fonction n'est pas concepteur ou chef de projet.
70
Noms de corrélation
Dans un Trigger ligne, il est possible d'accéder à l'ancienne et à la
nouvelle valeur d'un attribut modifié du tuple en cours de
traitement.

Les noms de corrélation permettent de désigner ces deux valeurs.

Nouvelle valeur du tuple: NEW


Ancienne valeur du tuple: OLD

Exemple:
Ancien salaire: (avant mise à jour) OLD.Salaire
Nouveau salaire (après mise à jour): NEW.Salaire
71
Noms de corrélation
Pur un Trigger déclenché par une instruction INSERT,
seules les nouvelles valeurs des attributs peuvent être
consultées (NEW).

Pour un Trigger déclenché par une instruction DELETE,


seules les anciennes valeurs des attributs peuvent être
consultées (OLD).

72
Trigger ligne
CREATE TRIGGER modif_salaire
AFTER UPDATE Salaire ON Employé
FOR EACH ROW WHEN (old.Salaire < 250000.00)
...

Le Trigger ne s'exécute que pour les employés pour


lesquels l'ancien salaire est inférieur à 250000.00DA.

Si le l'ancien salaire est NULL le Trigger ne s'exécutera


pas non plus.

73
Corps du Trigger
Le corps du Trigger est constitué d'un bloc PL/SQL. Il
peut contenir des instructions SQL et du code de
contrôle PL/SQL.

Le code PL/SQL constituant le corps du Trigger peut


faire appel à des fonctions ou des procédures stockés
déjà définies.

74
Restrictions
Seules les instructions DML(SELECT, INSERT, UPDATE,
DELETE) sont autorisées dans le corps d'un Trigger. Il n'est pas
permis d'utiliser les instructions DDL (CREATE, ALTER, DROP).
Un trigger ne peut utiliser les instructions de contrôle de
transactions COMMIT, ROLLBACK…

Une Trigger ligne ne peut ni lire, ni modifier la table concernée


par l'évènement ayant déclenché ce Trigger (table mutante). Pour
réaliser ce type d'opération il faut créer une table temporaire
répliquant les données de cette table.

Il est possible de déclencher des Triggers en cascade. Oracle


autorise des cascade de 32 Triggers au maximum.
75
Exemple
Ecrire un Trigger vérifiant que le nouveau salaire d'un
employé après modification est supérieur à l'ancien salaire
(uniquement pour les employés ayant un salaire de moins de
250000.00DA).

CREATE TRIGGER modif_salaire


BEFORE UPDATE Salaire ON Employé
FOR EACH ROW WHEN(old.Salaire <250000.00)
BEGIN
IF :old.Salaire > :new.Salaire THEN
RAISE_APPLICATION_ERROR(-20545, 'Nouveau salaire trop faible');
END IF;
END;

Les noms de corrélation doivent être précédés par ':' (Sauf dans la clause WHEN).

76
Exemple
Ecrire un Trigger vérifiant que les dates de début et de fin d'affectation
sont bornées par les dates de début et de fin du projet auquel correspond
l'affectation.

CREATE TRIGGER insert_affectation


BEFORE INSERT ON Affectation
FOR EACH ROW
DECLARE
v_debut DATE;
v_fin DATE;
BEGIN
SELECT Date_Début, Date_Fin INTO v_debut, v_fin
FROM Projet
WHERE Num_Projet = :NEW.Num_Projet;
IF :NEW.Debut_Affect < v_debut OR :NEW.Fin_Affect > v_fin THEN
RAISE_APPLICATION_ERROR(-20544, 'Affectation hors période de projet');
END IF;
END;

77
Référencement
Si une table du schéma porte le nom new (resp. old) il est
impossible d'utiliser les noms de corrélation (new et old). Le
SGBD interprétera ces noms comme les noms des tables du
schéma.

Pour remédier à cela il est possible d'associer ces noms de


corrélation à des références (alias).

Pour cela il suffit d'utiliser la clause:


REFERNCING OLD AS o NEW AS n

78
Référencement
CREATE TRIGGER insert_affectation
BEFORE INSERT ON Affectation
REFERENCING NEW AS nouv
FOR EACH ROW
DECLARE
v_debut DATE;
v_fin DATE;
BEGIN
SELECT Date_Début, Date_Fin INTO v_debut, v_fin
FROM Projet
WHERE Num_Projet = :nouv.Num_Projet;
IF :nouv.Debut_Affect < v_debut OR :nouv.Fin_Affect > v_fin THEN
RAISE_APPLICATION_ERROR(-20544, 'Affectation hors période de
projet');
END IF;
END;

79
Exercice
Ecrivez des Triggers permettant de:
1. Insérer chaque employé supprimé de la table
employé et dont l'âge est supérieur à 65 ans dans la
table retraité.

2. Vérifier pour une nouvelle affectation que l'employé


affecté a un salaire inférieur ou égal à son supérieur.

3. Empêcher la modification d'un projet qui a déjà


commencé.

80
Corrigé
CREATE OR REPLACE TRIGGER suppr_employe
BEFORE DELETE ON Employé
FOR EACH ROW WHEN (OLD.Date_Naissance < '08/05/1948')
BEGIN
INSERT INTO Retraité VALUES(:OLD.Num_Employé, :OLD.Nom,
:OLD.Prénom, :OLD.Date_Naissance, :OLD.Fonction, :OLD.Salaire);
END;

81
Corrigé
CREATE OR REPLACE TRIGGER insert_affect
BEFORE INSERT ON Affectation
FOR EACH ROW WHEN (NEW.Supérieur IS NOT NULL)
DECLARE
v_sal_emp Employé.Salaire%TYPE;
v_sal_sup Employé.Salaire%TYPE;
BEGIN
SELECT Salaire INTO v_sal_emp FROM Employé WHERE Num_Employé =
:NEW.Num_Employé;
SELECT Salaire INTO v_sal_sup FROM Employé WHERE Num_Employé =
:NEW.Supérieur;
IF v_sal_emp > v_sal_sup THEN
RAISE_APPLICATION_ERROR(-20420, 'Salaire du supérieur trop faible');
END IF;
END;

82
Corrigé
CREATE OR REPLACE TRIGGER modif_proj_comm
BEFORE UPDATE ON Projet
FOR EACH ROW
BEGIN
IF :OLD.Date_Début < SYSDATE THEN
RAISE_APPLICATION_ERROR(-20147, 'Projet ayant débuté.
Modification impossible');
END IF;
END;

83

Вам также может понравиться