Академический Документы
Профессиональный Документы
Культура Документы
Semestre 4
Mehdi Benzine
Introduction
SQL est un langage déclaratif non procédural
4
Blocs PL/SQL
Le langage PL/SQL permet de définir 3 types de blocs:
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;
/
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.
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
9
Variables
Une variable peut:
1. être initialisée au moment de sa déclaration
var type := valeur;
v_salaire NUMBER (7,2) := 42000;
10
Exemple 1
DECLARE
v_emp Employé%ROWTYPE;
BEGIN
11
RECORD
RECORD permet de définir un nouveau type composé de
champs élémentaires. (équivalent aux structures C)
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;
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
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:
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%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.
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:
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.
28
Ouvrir un curseur
OPEN nom_curseur;
Exemple:
DECLARE
…
BEGIN
OPEN projets;
29
Lecture des tuples
FETCH nom_curseur INTO var1[, var2, …];
Ou
FETCH nom_curseur INTO record;
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.
Après avoir lu tout les tuples le dernier FETCH ne retourne plus rien.
CLOSE nom_curseur;
Exemple:
CLOSE projets;
34
Attributs du curseur explicite
Le curseur explicite dispose des attributs suivants:
%FOUND
%NOTFOUND
%ROWCOUNT
%ISOPEN
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;
39
Paramètres
Il faut distinguer trois types de paramètres:
40
Procédure stockée
CREATE [OR REPLACE] PROCEDURE nom [paramètres]
IS
DECLARE
…
BEGIN
…
END;
42
Procédure
Pour tester cette procédure il suffit de taper dans Oracle
SQL developer:
EXECUTE affiche_budget(122);
Affiche_budget(122);
43
Fonction
Les fonctions PL/SQL sont des procédures stockées
ayant une valeur de retour.
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;
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.
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.
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.
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 '/'.
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
…
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.
59
Triggers sous Oracle
Pour vérifier ces contraintes d'intégrité, il est possible
d'utiliser des Triggers (déclencheurs).
60
Schéma Exemple
Projet (Num_Projet, Description, Date_Début, Date_Fin, Budget)
61
Relation Employé
62
Déclaration de Trigger
Un trigger peut être exécuté avant (BEFORE) ou après (AFTER) l'évènement
déclencheur.
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)
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.
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.
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.
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).
72
Trigger ligne
CREATE TRIGGER modif_salaire
AFTER UPDATE Salaire ON Employé
FOR EACH ROW WHEN (old.Salaire < 250000.00)
...
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.
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…
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.
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.
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é.
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