Vous êtes sur la page 1sur 85

CONCEPTS DE BASE

LANGAGE PL/SQL

2022-2023 Enis BELHASSEN (enis.belhassen@gmail.com)


Langage PL/SQL vs SQL
2

 SQL : langage ensembliste non procédural


 Ensemble de requêtes distinctes
 Langage assertionnel de 4ème génération : on décrit le résultat sans dire
comment il faut accéder aux données
 Possibilité d’encapsulation dans un langage hôte de 3ème génération
 PL/SQL
 ‘Procedural Language’ : surcouche procédurale à SQL (traitements
itératifs, contrôles, affectations, exceptions, ….)
 Un langage procédural pour lier plusieurs requêtes SQL avec des
variables et dans les structures de programmation habituelles
 L’intérêt du PL/SQL est de pouvoir mélanger la puissance des instructions
SQL avec la souplesse d’un langage procédural
Avantages du PL/SQL
3

 Traitements procéduraux : la gestion des variables


et les structures de contrôle (conditionnelles et
itératives)
 Fonctionnalités supplémentaires : la gestion des
curseurs et le traitement des erreurs (exceptions)
 Amélioration des performances : plusieurs
instructions sont regroupées dans une unité (bloc) qui
ne génèrera qu’un "accès" à la base (à la place
d’un accès par instruction)
Avantages du PL/SQL
4

 Modularité : un bloc peut être nommé pour devenir


une procédure ou une fonction cataloguée et
réutilisable. Une procédure, ou fonction, cataloguée
peut être incluse dans un paquetage (package)
 Portabilité : un programme PL/SQL est indépendant
du système d’exploitation qui héberge le serveur
Oracle. En changeant de système, les applicatifs
n’ont pas à être modifiés
Structure d’un bloc PL/SQL
5

 Section DECLARE (section optionnelle) pour la déclaration des :


 Variables locales simples
[DECLARE
 Variables tableaux
 Curseurs / Exceptions -- Déclarations]

 Section BEGIN (section obligatoire) BEGIN


 Section des ordres exécutables -- Instructions
 Ordres SQL [EXCEPTION
 Ordres PL -- Erreurs]
 Section EXCEPTION (section optionnelle) END;
 Traitement des erreurs interceptées
/
 Exceptions SQL ou utilisateur
 Il est possible d’ajouter des commentaires à un bloc :
-- commentaire sur une seule ligne (mono-lignes)
/*... ... */ commentaire sur plusieurs lignes (multi-lignes)
Structure d’un bloc PL/SQL
6

 Un bloc peut être imbriqué dans le code d’un autre bloc :


sous-bloc.
 Un sous-bloc peut aussi se trouver dans la partie des
exceptions.
 Un sous-bloc commence par BEGIN et se termine par END.

PL/SQL n’est pas


sensible à la casse
(not case sensitive)
Types de blocs PL/SQL
7

 Bloc Anonyme
 Stockéen-dehors de la base de données
 Compilé et exécuté à la volée

 Procédure Stockée :
 Compilée séparément
 Stockée de façon permanente dans la BD

 Déclencheur (Trigger)
 Procédure stockée associée à une table
 Exécution automatique sur événement
Commandes de dialogue – SQL*Plus
8

 PROMPT texte : afficher le texte


 ACCEPT variable [PROMPT texte] : forcer SQL*Plus à
attendre une valeur pour définir une variable permanente
Variables – SQL*Plus
9

 Variables lues par un ACCEPT …. PROMPT


SQL*Plus ACCEPT var PROMPT 'Entrer la valeur : '

DECLARE
-- déclarations
BEGIN
PL/SQL -- &var si numérique
-- '&var' si chaine de caractères
END;
/
SQL*Plus -- Ordre SQL .....
Package DBMS_OUTPUT – SQL*Plus
10

 Messages enregistrés dans une mémoire tampon


côté serveur
 La mémoire tampon est affichée sur le poste client à
la fin Serveur ORACLE
Client SQL*PLUS BEGIN
DBMS_OUTPUT.PUT_LINE('Message1');
DBMS_OUTPUT.PUT_LINE('Message2');
Message1 DBMS_OUTPUT.PUT_LINE('Message3');
Message2 END;
Message3

Message1
Message2
Message3
SQL>SET SERVEROUT ON
Mémoire tampon
Types de Variables PL/SQL
11

 Variables locales:
 De type simple: type de base ou booléen
 Faisant référence à la métabase (dictionnaire de
données de Oracle)
 De type composé : Tableau, Record

 Variables Extérieures:
 Variablesd’un langage hôte (ex: C) (préfixés par : )
 Paramètres (ex: SQL interactif préfixés par &)
Types de Variables
12
Opérateurs SQL
13

 Opérateur d’affectation :=
 Opérateurs arithmétiques + - / * **
 Opérateur de concaténation ||
 Opérateurs de comparaison
= < > <= >= <> != IS NULL LIKE BETWEEN IN
 Opérateurs logiques AND, OR, NOT
Variables simples
14

 Déclaration :
variable_name [CONSTANT] datatype
[NOT NULL] [:= | DEFAULT initial_value];

 Le nom d’une variable (identificateur) commence


par une lettre suivie (optionnel) de symboles (lettres,
chiffres, $, _ , #).
 Un identificateur peut contenir jusqu’à 30 caractères
 Les autres symboles sont interdits (& , - / espace …)
Variables simples
15

 Variables de type SQL


Date_nais DATE;
nom VARCHAR2(30) DEFAULT 'Bonjour';
minimum CONSTANT INTEGER := 5;
salaire NUMBER(8,2);
debut NUMBER NOT NULL := 10;

 Variables de type booléen (TRUE, FALSE, NULL)


fin BOOLEAN;
reponse BOOLEAN DEFAULT TRUE;
ok BOOLEAN := TRUE;
Variables référençant la métabase
16

 Référence à une colonne (table, vue)


vsalaire emp.sal%TYPE;
vnom emp.ename%TYPE;

 Référence à une ligne (table, vue)


vemploye emp%ROWTYPE;

 Variable de type ‘struct’


 Contenu d’une variable : variable.colonne
vemploye.ename

 Référence une variable précédemment définie


commi number(7,2);
Salaire commi%TYPE;
Variables référençant la métabase
17

 Exemple : déclaration et utilisation d'une variable ROWTYPE


var_emp qui contient le même nombre de champs que la
table EMP

declare
var_emp emp%rowtype;
begin
var_emp.empno := 1234;
var_emp.ename := 'Salah';

dbms_output.put_line ('Num emp : '||var_emp.empno);


dbms_output.put_line ('Nom emp : '||var_emp.ename);
dbms_output.put_line ('Job emp : '||var_emp.job);
end;
/
Conversion de type de données
18

 Fonctions de conversion :
TO_CHAR, TO_DATE, TO_NUMBER

v_date1 := to_date('01/01/1999', 'dd/mm/yyyy');


v_date2 := to_date('01-jan-1999', 'dd-mon-yyyy');
v_date_systeme := to_char(sysdate, 'dd/mm/yyyy');
v_heure_systeme := to_char(sysdate, 'hh24:mi:ss');
v_date_systeme_complete :=
to_char(sysdate, 'dd/mm/yyyy hh24:mi:ss');
v_num_str := to_char(130);
v_num := to_number('140');
Traitements conditionnels
19

 Structure alternative ou conditionnelle


 IF …. THEN ….. ELSIF …… ELSE ……END IF;
IF condition1 THEN
instructions1;
[ELSIF condition2 THEN
instructions2;]
[… ELSIF condition3 THEN
instructions3;]
[ELSE
instructions;]
END IF;

 Une instruction IF peut contenir plusieurs clauses ELSIF,


mais une seule clause ELSE (optionnelle).
Structure alternative : CASE
20

 Choix selon la valeur d’une variable/une expression


CASE variable
WHEN valeur1 THEN action1;
WHEN valeur2 THEN action2;
………
ELSE action;
END CASE;

CASE
WHEN condition1 THEN action1;
WHEN condition2 THEN action2;
………
ELSE action;
END CASE;
Structure alternative : CASE
21

DECLARE
note varchar2(1) := 'D';
BEGIN
CASE note
when 'A' then dbms_output.put_line('Excellent');
when 'B' then dbms_output.put_line('Très Bien');
when 'C' then dbms_output.put_line('Bien');
when 'D' then dbms_output.put_line('Passable');
when 'E' then dbms_output.put_line('Mauvais');
else dbms_output.put_line('Valeur incorrecte');
END CASE;
END;
/
Structure alternative : CASE
22
Traitements itératifs
23

 LOOP
LOOP
instructions;
EXIT WHEN (condition);
END LOOP;

 FOR
FOR (indice IN [REVERSE] borne1..borne2) LOOP
instructions;
END LOOP;

 WHILE
WHILE (condition) LOOP
instructions;
END LOOP;
Structures itératives
24

------ Affichage des nombres divisibles par 4 compris entre 1 et 20


------ Boucle FOR

BEGIN
dbms_output.put_line ('Les nombres divisibles par 4 sont : ');
FOR i IN 4..20 LOOP
IF (mod(i,4) = 0) THEN
dbms_output.put_line (to_char(i) || '-');
END IF;
END LOOP;
END;
/
Structures itératives
25
Structures itératives
26

------ Affichage des nombres divisibles par 4 compris entre 1 et 20


------ Boucle WHILE
DECLARE
i number (2);
BEGIN
dbms_output.put_line ('Les nombres divisibles par 4 sont : ');
i := 4;
WHILE (i <= 20) LOOP
IF (mod(i,4) = 0) THEN -- mod(i,4) : reste de la division de i par 4
dbms_output.put_line (to_char(i) || ' – ');
END IF;
i := i + 1;
END LOOP;
END;
/
Structures itératives
27

------ Affichage des nombres divisibles par 4 compris entre 1 et 20


------ Boucle LOOP
DECLARE
max_nombre CONSTANT number(3) := 20;
i number (2);
BEGIN
dbms_output.put_line ('Les nombres divisibles par 4 sont : ');
i := 4;
LOOP
IF (mod(i,4) = 0) THEN -- mod(i,4) : reste de la division de i par 4
dbms_output.put_line (to_char(i) || ' – ');
END IF;
i := i + 1;
EXIT WHEN (i > 20);
END LOOP;
END;
/
Exemple – Années Bissextiles
28

Affichage des années bissextiles comprise entre ANNEE1 et


ANNEE2

ACCEPT ANNEE1 PROMPT 'Entrer la valeur de annee 1 '


ACCEPT ANNEE2 PROMPT 'Entrer la valeur de annee 2 '

BEGIN
dbms_output.put_line ('Les annees bissextiles sont : ');
FOR i IN &ANNEE1 .. &ANNEE2 LOOP
IF ( (MOD (i,4) = 0 AND MOD(i, 100) != 0) OR MOD(i, 400) = 0 )
THEN dbms_output.put_line(i);
END IF;
END LOOP;
END;
/
SELECT …. INTO … (mono – ligne)
29

 Toute valeur de colonne est rangée dans une


variable avec INTO
DECLARE
nom emp.ename%type;
fonction emp.job%type;
salaire emp.sal%type;
BEGIN
SELECT ename, job, sal
INTO nom, fonction, salaire
FROM emp
WHERE empno = 7369;

dbms_output.put_line ('Nom de emp 7369 : '||nom);


dbms_output.put_line ('Fonction de emp 7369 : '||fonction);
dbms_output.put_line ('Salaire de emp 7369 : '||salaire);
END;
/
SELECT …. INTO … (mono – ligne)
30

 Variable ROWTYPE
DECLARE
vdept dept%rowtype;
BEGIN
SELECT *
INTO vdept
FROM dept
WHERE deptno = 40;

DBMS_OUTPUT.PUT_LINE('Nom dept 40 : '|| vdept.dname);


DBMS_OUTPUT.PUT_LINE('Local dept 40 : '|| vdept.loc);
END;
/
Curseurs (Sélection multi – ligne)
31

 Curseur : Structure de données permettant de stocker


le résultat d’une requête qui retourne plusieurs lignes
 Curseur implicite : généré et géré par le noyau de
Oracle pour chaque ordre SQL
 SELECT t.* FROM table t WHERE ……
 t est un curseur utilisé par SQL

 Curseur explicite : généré par l’utilisateur pour traiter


un ordre SELECT qui ramène plusieurs lignes
 Déclaration
 Ouverture du curseur
 Traitement des lignes
 Fermeture du curseur
Démarche générale des curseurs
32

 Déclaration du curseur : DECLARE


 Ordre SQL sans exécution
 Ouverture du curseur : OPEN
 SQL ‘monte‘ les lignes sélectionnées en mémoire Verrouillage
préventif possible
 Sélection d’une ligne : FETCH
 Chaque FETCH ramène une ligne dans le programme client
 Tant qu’il existe une ligne en mémoire

 Fermeture du curseur : CLOSE


 Récupération de l’espace mémoire
Traitement d’un curseur
33

Programme PL/SQL
Mémoire
FETCH

variables

DECLARE
CURSOR c1 IS SELECT ……;
BEGIN
OPEN c1;
FETCH c1 INTO ………;
WHILE (c1%FOUND) LOOP
………
……… OPEN
FETCH c1 INTO ………;
END LOOP;
CLOSE c1;
END;
BD
Attributs d’un Curseur
34

 Curseur%FOUND
 Variable
booléenne : est égal à TRUE si le dernier
FETCH a retourné un résultat
 Curseur%NOTFOUND
 Variable booléenne opposée au précédent : est égal à
TRUE si le dernier FETCH n’a pas retourné un résultat
 Curseur%ROWCOUNT
 Variable numérique : retourne le nombre de lignes lues
 Curseur%ISOPEN
 Variable booléenne : est égal à TRUE si le curseur est
ouvert
Gestion ‘classique’ d’un curseur
35

DECLARE
CURSOR emp_cursor IS -- déclarer le curseur
SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno;

emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor ; -- Ouvrir le curseur
LOOP
FETCH emp_cursor INTO emp_record; -- avancer au tuple suivant
EXIT WHEN emp_cursor%NOTFOUND; -- sortir si la fin du curseur
-- est détectée
DBMS_OUTPUT.PUT_LINE('L''employe '|| emp_record.ename ||
' travaille dans le departement ' || emp_record.dname);
END LOOP;
CLOSE emp_cursor; -- fermer le curseur
END;
/
Gestion ‘classique’ d’un curseur
36
Gestion ‘classique’ d’un curseur
37

DECLARE
CURSOR emp_cursor IS -- déclarer le curseur
SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno;

emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor ; -- Ouvrir le curseur
LOOP
FETCH emp_cursor INTO emp_record; -- avancer au tuple suivant
EXIT WHEN emp_cursor%NOTFOUND; -- sortir si la fin du curseur
-- est détectée
DBMS_OUTPUT.PUT_LINE(emp_cursor%ROWCOUNT||' - L''employe '||
emp_record.ename ||
' travaille dans le departement '
|| emp_record.dname);
END LOOP;
CLOSE emp_cursor; -- fermer le curseur
END;
/
Gestion ‘classique’ d’un curseur
38 DECLARE
CURSOR emp_cursor IS -- déclarer le curseur
SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno;

nom_emp emp.ename%TYPE;
nom_dept dept.dname%TYPE;
BEGIN
OPEN emp_cursor ; -- Ouvrir le curseur
LOOP
FETCH emp_cursor INTO nom_emp, nom_dept;
-- avancer au tuple suivant
EXIT WHEN emp_cursor%NOTFOUND; -- sortir si la fin du curseur
-- est détectée
DBMS_OUTPUT.PUT_LINE(emp_cursor%ROWCOUNT||' - L''employe '||
nom_emp ||
' travaille dans le departement '||
nom_dept);
END LOOP;
CLOSE emp_cursor; -- fermer le curseur
END;
/
Gestion ‘classique’ d’un curseur
39

DECLARE
CURSOR emp_cursor IS -- déclarer le curseur
SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno;
emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor; -- Ouvrir le curseur
FETCH emp_cursor INTO emp_record; -- avancer au premier tuple
WHILE (emp_cursor%FOUND) LOOP -- sortir si aucun tuple
-- n’a été ramené par
-- le dernier fetch
DBMS_OUTPUT.PUT_LINE(emp_cursor%ROWCOUNT||' - L''employe '||
emp_record.ename ||
' travaille dans le departement '
|| emp_record.dname);

FETCH emp_cursor INTO emp_record; -- avancer au tuple suivant


END LOOP;
CLOSE emp_cursor; -- fermer le curseur
END;
/
Gestion ‘automatique’ d’un curseur
40

DECLARE
CURSOR emp_cursor IS -- déclarer le curseur
SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno;
BEGIN
-- Ouverture, parcours et fermeture automatique du curseur
FOR emp_record IN emp_cursor LOOP
DBMS_OUTPUT.PUT_LINE(emp_cursor%rowcount||' - L''employe '||
emp_record.ename ||
' travaille dans le departement ' ||
emp_record.dname);
END LOOP;
END;
/
Gestion ‘automatique’ d’un curseur
41

BEGIN
-- Déclaration, ouverture, parcours et fermeture
-- automatique du curseur
FOR emp_record IN ( SELECT ename, dname FROM emp, dept
WHERE emp.deptno = dept.deptno)
LOOP
DBMS_OUTPUT.PUT_LINE('L''employe '||
emp_record.ename ||
' travaille dans le departement '
|| emp_record.dname);
END LOOP;
END;
/
Curseurs paramétrés
42

ACCEPT num_dep PROMPT 'Entrer le numero du departement : '

DECLARE
CURSOR emp_cursor (p_dep EMP.deptno%TYPE) IS
SELECT ename, job, sal
FROM emp
WHERE deptno = p_dep;

v_employe emp_cursor%rowtype;
BEGIN
dbms_output.put_line ('Employes du dept. '||&num_dep);
open emp_cursor(&num_dep);
LOOP
fetch emp_cursor into v_employe;
exit when emp_cursor%notfound;
dbms_output.put_line (v_employe.ename|| ' - '|| v_employe.job ||
' : '|| v_employe.sal);
END LOOP;
close emp_cursor;
END;
/
Curseur - Clause CURRENT-OF
43

 la clause CURRENT-OF permet d’accéder


directement, en modification ou en suppression, à la
ligne que vient de renvoyer l’ordre FETCH.

 Au préalable, dans la déclaration du curseur, il faut


réserver les lignes qui seront modifiées par la pose
d’un verrou d’intention (...FOR UPDATE OF
colonne_à_modifier...).
Curseur - Clause CURRENT-OF
44

MODIFIER LA COLONNE COMM QUI DOIT ETRE EGALE À 5% SAL


SI LA COMMISSION EST NULL OU ÉGALE À 0

DECLARE
CURSOR emp_cursor IS
SELECT comm
FROM emp
FOR UPDATE OF comm;
BEGIN
FOR v_employe IN emp_cursor LOOP
IF v_employe.comm IS NULL or v_employe.comm = 0
THEN
UPDATE emp SET comm = sal * 0.05
WHERE CURRENT OF emp_cursor;
END IF;
END LOOP;

END;
/
Gestion des Exceptions
45

 Toute erreur (SQL ou applicative) entraîne automatiquement


un débranchement vers le paragraphe EXCEPTION :
Débranchement involontaire (erreur SQL)
BEGIN ou volontaire (erreur applicative)
instruction1;
instruction2;
……
instructionn;
EXCEPTION
WHEN exception1 THEN
………
WHEN exception2 THEN
………
WHEN OTHERS THEN
………
END;
Gestion des Exceptions
46

 Exceptions SQL déclenchée implicitement par une erreur Oracle


 Déjà définies (pas de déclaration) :
◼ DUP_VAL_ON_INDEX
◼ NO_DATA_FOUND / TOO_MANY_ROWS
◼ OTHERS

 Exceptions applicatives déclenchée explicitement par le programme


 Déclaration sans n°erreur (section DECLARE)
nomerreur EXCEPTION;
 Lever l'exception (section BEGIN)
RAISE nomerreur;
Gestion des Exceptions
47

 Fonctions PL/SQL pour la gestion d’erreurs


 SQLCODE : renvoyer la valeur numérique associée à la dernière
exception détectée
 SQLERRM : renvoyer le message associé au code de l’erreur
 Exceptions prédéfinies
Nom Code erreur Sqlcode Description
--------------------------------------------------------------------------------------------------
NO_DATA_FOUND ORA-01403 -1403 SELECT mono-ligne retournant 0 ligne
TOO_MANY_ROWS ORA-01422 -1422 SELECT mono-ligne retournant plus d’1 ligne
DUP_VAL_ON_INDEX ORA-00001 -1 Insertion d’une ligne en doublon
VALUE_ERROR ORA-06502 -6502 Erreur arithmétique, conversion ou limite de taille
ZERO_DIVIDE ORA-01476 -1476 Division par zéro
CURSOR_ALREADY_OPEN ORA-06511 -6511 Ouverture d’un curseur déjà ouvert
INVALID_NUMBER ORA-01722 -1722 Echec sur une conversion d’un chaîne de caractères
vers un nombre

Exemple de gestion d’exception
48

DECLARE
erreur EXCEPTION; ---- Déclaration exception
BEGIN

SELECT … INTO ……

IF ……… THEN RAISE erreur; ---- Levée exception


………
EXCEPTION
WHEN NO_DATA_FOUND THEN ---- Exception prédéfinie
………
WHEN erreur THEN ---- Traitement exception
………
WHEN OTHERS THEN ---- Exception prédéfinie
………
END;
Exemple de gestion d’exception
49

DECLARE
nbre_emp INTEGER;
aucun_emp EXCEPTION; ---- Déclaration exception
BEGIN
SELECT COUNT(*) INTO nbre_emp FROM emp;
IF nbre_emp =0 THEN
RAISE aucun_emp; ---- Levée exception
ELSE
DBMS_OUTPUT.PUT_LINE('La table EMP contient '||nbre_emp||' employes');
END IF;
EXCEPTION
WHEN aucun_emp THEN ---- Traitement exception
DBMS_OUTPUT.PUT_LINE('La table EMP est vide');
WHEN OTHERS THEN ---- Exception prédéfinie
DBMS_OUTPUT.PUT_LINE('Erreur inconnue ' || SQLERRM);
END;
/
Exemple de gestion d’exception
50

DECLARE
c INTEGER;
aucun_emp EXCEPTION; ---- Déclaration exception
BEGIN
SELECT COUNT(*) INTO c FROM emp;
IF c=0 THEN
RAISE aucun_emp; ---- Levée exception
………
EXCEPTION
WHEN aucun_emp THEN ---- Traitement exception
RAISE_APPLICATION_ERROR(-20501, 'La table EMP est vide');
………
END;
/

La procédure RAISE_APPLICATION_ERROR permet de définir des messages d'erreur


personnalisés en indiquant :
• numero_erreur : représente un entier négatif compris entre -20000 et -20999
• message : représente le texte du message d'une longueur maximum de 2048 octets
Exercice
51

Écrire un bloc anonyme PL/SQL permettant de calculer et d’afficher pour


chaque employé le montant de l’impôt et le net à payer :
 Définir et parcourir un curseur permettant de récupérer les noms des
employés (ENAME), leurs salaires (SAL) et leurs commissions (COMM)
 Pour chaque employé, afficher un message à l’écran indiquant son nom,
son salaire ainsi que le montant de l’impôt et le net à payer qui doivent
être calculés comme suit :
 Montant de l’impôt :
◼ Si le salaire est inférieur à 1000 alors l’impôt = 25% du salaire
◼ Si le salaire est compris entre 1000 et 1500 alors l’impôt = 30 % du salaire
◼ Si le salaire supérieur à 1500 alors l’impôt = 35 % du salaire

 Net à payer = salaire (SAL) + commission (COMM) – Montant de l’impôt


 Programmer l’exception prédéfinie OTHERS en affichant le message
suivant : « Erreur inconnue !!! »
Exercice
52

DECLARE
impot emp.sal%type;
net_payer emp.sal%type;
BEGIN
FOR emp_record IN (SELECT ename, sal, comm FROM emp)
LOOP
IF (emp_record.sal < 1000)
THEN impot := emp_record.sal * 0.25;
ELSIF emp_record.sal <= 1500
THEN impot := emp_record.sal * 0.3;
ELSE impot := emp_record.sal * 0.35;
END IF;
net_payer := emp_record.sal + nvl(emp_record.comm, 0) - impot;
DBMS_OUTPUT.PUT_LINE('L''employe '||emp_record.ename ||
' - Salaire = ' ||emp_record.sal|| ' - Impot = ' ||impot||' - Net a payer = ' ||net_payer);
END LOOP;
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Erreur inconnue !!!');
END;
/
PROCÉDURES –
FONCTIONS – PACKAGES

2022-2023 Enis BELHASSEN (enis.belhassen@gmail.com)


Procédures stockées
54

 Une procédure PL/SQL est un bloc nommé qui


exécute une ou plusieurs actions.
 Une procédure peut être stockée dans la base de
données, comme tout autre objet.

BD – Oracle
Procédure/Fonction
Stockée
Procédures stockées
55

CREATE [OR REPLACE] PROCEDURE nom-procédure


[(argument [mode] type, ...)] IS
bloc-procédure;

 argument : nom d’un paramètre formel


 mode : définit si le paramètre formel est en entrée (IN), en
sortie (OUT) ou en entrée-sortie (IN OUT). Par défaut : IN
 type : le type du paramètre formel
 bloc-procédure : le corps PL/SQL de la procédure
Procédures stockées
56

 Exemple :
CREATE OR REPLACE PROCEDURE modifierTitre
(num IN film.numFilm%TYPE, nouvTitre IN film.titre%TYPE) IS
BEGIN
UPDATE film SET titre = UPPER(nouvTitre)
WHERE numFilm = num;
END modifierTitre;

 Utiliser ‘SHOW ERRORS’ pour voir les erreurs de la


compilation.
 Pour exécuter la procédure :
execute nom_proc (valeurs des paramètres)
Procédures stockées
57

Ecrire une procédure pour afficher le nom et le salaire d’un


employé dont le numéro est spécifié comme paramètre
CREATE OR REPLACE PROCEDURE affiche_salaire
(num_employe IN EMP.empno%type) IS
v_ename EMP.ename%type;
v_sal EMP.sal%type;
BEGIN
SELECT ename, sal
INTO v_ename, v_sal
FROM EMP
WHERE empno = num_employe;

DBMS_OUTPUT.PUT_LINE(num_employe||' '||v_ename||'
'||v_sal);
END;
/
Procédures stockées
58

 Pour tester une procédure sous SQL*Plus :


EXECUTE affiche_salaire (7369)

 Ou créer un bloc PL/SQL dans lequel on fait appel à


la procédure :
BEGIN
affiche_salaire (7369);
END;
/
Procédures stockées
59

Ecrire une procédure qui permet de retourner dans des


paramètres OUT le nom et le salaire d’un employé dont le
numéro est spécifié comme paramètre IN
CREATE OR REPLACE PROCEDURE affiche_salaire
(num_employe IN EMP.empno%type,
v_ename OUT EMP.ename%type,
v_sal OUT EMP.sal%type) IS
BEGIN
SELECT ename, sal
INTO v_ename, v_sal
FROM EMP
WHERE empno = num_employe;
END;
/
Procédures stockées
60

 Pour tester une procédure avec des paramètres OUT sous


SQL*Plus : créer un bloc PL/SQL dans lequel on fait appel à
la procédure :

DECLARE
nom_emp EMP.ename%type;
sal_emp EMP.sal%type;
BEGIN
affiche_salaire (7369, nom_emp, sal_emp);
DBMS_OUTPUT.PUT_LINE(nom_emp||' '|| sal_emp);
END;
/
Procédures stockées
61

 Suppression d’une procédure :


DROP PROCEDURE nom_proc;

 Dictionnaire de données :
USER_SOURCE, USER_OBJECTS, USER_ERRORS
Fonctions stockées
62

 Les fonctions stockées sont des blocs PL/SQL


nommés qui retournent une valeur.

 Une fonction peut être stockée dans la base de


données comme les autres objets de la base de
données.
Fonctions stockées
63

CREATE [OR REPLACE] FUNCTION nom-fonction


[(argument [IN] type, ...)]
RETURN type-retour IS
bloc-fonction;

 Les paramètres sont forcément en entrée (IN)


 Dans le bloc-fonction :
RETURN nom-variable;
Fonctions stockées
64

 Exemple :
CREATE OR REPLACE FUNCTION moyenneDuree (dd IN DATE )
RETURN NUMBER IS
moy NUMBER(8) := 0;
BEGIN
SELECT AVG(duree)
INTO moy
FROM film WHERE dateFilm <= dd;
RETURN moy;
END moyenneDuree;
Fonctions stockées
65

Ecrire une fonction qui retourne la somme du salaire et des


commissions d’un employé dont le numéro est spécifié comme
paramètre
CREATE OR REPLACE FUNCTION SALAIRE_COMMISSION
(v_num IN EMP.empno%type)
RETURN number IS
v_resultat EMP.sal%type;
BEGIN
SELECT sal + nvl(comm, 0) INTO v_resultat
FROM EMP
WHERE empno = v_num;

Return (v_resultat);
END;
/
Fonctions stockées
66

 Pour tester une fonction avec une requête select :


select SALAIRE_COMMISSION(7369) from dual;
 Ou créer un bloc PL/SQL dans lequel on fait appel à la
fonction :
DECLARE
v_sal number;
BEGIN
v_sal := SALAIRE_COMMISSION(7369);
DBMS_OUTPUT.PUT_LINE('Salaire : '|| v_sal);
END;
/
 Suppression d’une fonction :
DROP FUNCTION nom_fonction;
Packages
67

 Un package est un ensemble de procédures, de


fonctions, de variables, de constantes, de curseurs et
d’exceptions stockés dans la base de données
Oracle.
 Un package ne peut être appelé ni paramétré.
 Pour concevoir un package, on doit créer une
spécification et un corps.
Packages
68

 Deux parties distinctes dans un package (chaque


partie doit être créée et compilée séparément) :
 La partie déclaration ou spécification qui contient la
déclaration des procédures, fonctions et variables, …
 La partie corps, ou body, qui contient la définition des
procédures ou fonctions de type public déclarées dans
la partie spécification ainsi que les déclarations de
procédures ou fonctions de type privé
Packages - Spécification
69

CREATE [OR REPLACE] PACKAGE


nom-package IS
[déclaration-de-variable;]
[déclaration-de-curseur;]
[déclaration-de-procédure;]
[déclaration-de-fonction;]
[déclaration-d’exception;]
END nom-package;
Packages - Définition
70

CREATE [OR REPLACE] PACKAGE BODY


nom-package IS
[définition-de-variable;]
[définition-de-curseur;]
[définition-de-procédure;]
[définition-de-fonction;]
[définition-d’exception;]
END nom-package;
Package - Exercice
71

 Créer un package (pack1) contenant :


 une variable global initialisée à 10
 une fonction (fonct1) avec 1 paramètre en entrée (no
employé) et retourne le salaire de l’employé
 un curseur (cur_max) qui ramène le salaire maximal de
tous les employés
 une fonction (fonct2) qui retourne le salaire maximal de
tous les employés en utilisant le curseur.
 une procédure (pro1) avec 1 paramètre en entrée (le
no employé) et 2 paramètres en sortie le nom et le
salaire de l’employé.
Packages - Spécification
72

CREATE OR REPLACE PACKAGE pack1 IS


p_global number := 10;

FUNCTION fonct1(p_num IN number) RETURN number;

CURSOR cur_max IS SELECT max(sal) FROM EMP;

FUNCTION fonct2 RETURN number;

PROCEDURE proc1(p_num IN number,


p_nom OUT varchar2, p_sal OUT number);

END;
Packages - BODY
73

CREATE OR REPLACE PACKAGE BODY pack1 IS


FUNCTION fonct1(p_num IN number) RETURN number IS
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno = p_num;
return v_sal;
end;

FUNCTION fonct2 RETURN number IS


v_max number;
begin
OPEN cur_max;
FETCH cur_max INTO v_max;
CLOSE cur_max;
p_global := v_max;
Return v_max;
end;
Packages - Spécification
74 FUNCTION SALAIRE_COMMISSION (v_num IN EMP.empno%type)
RETURN number IS
v_resultat EMP.sal%type := 0;
BEGIN
SELECT sal + nvl(comm, 0) INTO v_resultat
FROM EMP
WHERE empno = v_num;

Return (v_resultat);
END;

PROCEDURE proc1(p_num IN number,


p_nom OUT varchar2, p_sal OUT number) IS
begin
select ename into p_nom
from emp where empno = p_num;
p_sal := SALAIRE_COMMISSION(p_num);
exception
when others then p_nom := null; p_sal := null;
end;
END;
/
Packages - Spécification
75

 Exécution d’une fonction d’un package :


select pack1.fonct1(7902) from dual;
 Exécution d’une procédure d’un package :
declare
v_nom emp.ename%type;
v_salaire number;
begin
pack1.proc1 (7902, v_nom, v_salaire);
dbms_output.put_line(v_nom||'-'||v_salaire);
end;
 Affichage d’une variable globale d’un package
begin
dbms_output.put_line(pack1.p_global);
end;
Packages - Spécification
76

 Suppression du package body :


DROP PACKAGE BODY nom_package;

 Suppression spécification du package :


DROP PACKAGE nom_package;
TRIGGERS

2022-2023 Enis BELHASSEN (enis.belhassen@gmail.com)


Triggers en PL/SQL
78

 Un trigger est un programme PL/SQL exécuté quand un


événement arrive : INSERT, UPDATE ou DELETE

 La forme générale d'un trigger est :


CREATE [OR REPLACE] TRIGGER nom_trigger
{BEFORE | AFTER } INSERT ou UPDATE ou DELETE
ON table_mis_à_jour
[ ... options supplémentaires...]
[DECLARE
définition_variables_constantes]
BEGIN
instructions
[EXCEPTION
programmation_exceptions]
END;
Triggers en PL/SQL
79

 Un trigger est activé dès sa création

 Commande pour désactiver un trigger :


ALTER TRIGGER nom_trigger DISABLE;

 Commande pour activer un trigger :


ALTER TRIGGER nom_trigger ENABLE;

 Commande pour supprimer un trigger :


DROP TRIGGER nom_trigger;
Triggers en PL/SQL - after insert
80

 Afficher un message après l'insertion d'un employé


create or replace trigger monTrigger1
after insert on emp
begin
dbms_output.put_line('OK');
end;

 Test avec une requête insert :


SQL> insert into emp (empno) values (123);
OK <-- message affiché par le trigger

1 ligne crÚÚe. <-- message affiché par Oracle (SQLPlus)


Triggers en PL/SQL - after update
81

 Afficher un message après la mise à jour d'un employé


create or replace trigger monTrigger2
after update on emp
begin
dbms_output.put_line('MAJ OK');
end;

 Test avec une requête update :


SQL> update emp set sal=sal*1.2 where deptno=10;
MAJ OK

3 lignes mises Ó jour.


Triggers en PL/SQL - after update
82

 Afficher un message après la mise à jour d’un attribut spécifié


create or replace trigger monTrigger2
after update of sal on emp
begin
dbms_output.put_line('Update Salaire');
end;

 Test avec des requêtes update :


SQL> update emp set sal = sal*1.2 where deptno = 10;
Update Salaire <-- Mise à jour du salaire : trigger exécuté

3 lignes mises Ó jour.

SQL> update emp set comm = 0 where deptno = 20;

5 lignes mises Ó jour.<-- Mise à jour comm : trigger non exécuté


Triggers en PL/SQL - FOR EACH ROW
83

 Une fois lancé, un trigger peut exécuter son code pour chaque
tuple touché par la mise à jour : utiliser la clause FOR EACH ROW
create or replace trigger monTrigger2
after update of sal on emp for each row
begin
dbms_output.put_line('Update Salaire');
end;
/

 Test avec une requête update :


SQL> update emp set sal = sal*1.2 where deptno = 10;
Update Salaire <-- Message affiché pour chaque ligne màj
Update Salaire
Update Salaire

3 lignes mises Ó jour.


Triggers en PL/SQL - FOR EACH ROW
84

 On peut accéder aux valeurs des champs avant et après la mise


à jour : valeurs préfixées par OLD et NEW
create or replace trigger monTrigger2
after update of sal on emp for each row
begin
dbms_output.put_line(:new.ename||' - Nouveau Sal: '||
:new.sal||' - Ancien Sal : ' || :old.sal);
end;
/
 Test avec une requête update :
SQL> update emp set sal = sal*1.2 where deptno = 10;
KING - Nouveau Sal: 6000 - Ancien Sal : 5000
CLARK - Nouveau Sal: 2940 - Ancien Sal : 2450
MILLER - Nouveau Sal: 1560 - Ancien Sal : 1300

3 lignes mises Ó jour.


Triggers en PL/SQL - FOR EACH ROW
85

 On peut filtrer sur quels tuples sera exécuté le corps du trigger :


clause WHEN
create or replace trigger monTrigger2
after update of sal on emp for each row
when (old.sal < 3000)
begin
dbms_output.put_line(:new.ename||' - Nouveau Sal: '||
:new.sal||' - Ancien Sal : ' || :old.sal);
end;
/
 Test avec une requête update :
SQL> update emp set sal = sal*1.2 where deptno = 10;
CLARK - Nouveau Sal: 3528 - Ancien Sal : 2940
MILLER - Nouveau Sal: 1872 - Ancien Sal : 1560

3 lignes mises Ó jour.

Vous aimerez peut-être aussi