Documente Academic
Documente Profesional
Documente Cultură
Cours III
Introduction au PL/SQL
Chargé de cours :
Saïd TALBI
1 Introduction
3 Déclarations
4 Instructions PL/SQL
6 Procédures et fonctions
1
1 Introduction
PL/SQL permet de traiter le résultat d'une requête tuple par tuple. La notion de
CURSOR sert à cet effet
3
[<entete_du_bloc>]
[DECLARE
<constantes>
<variables>
<cursors>
<exceptions_utilisateurs>]
BEGIN
<instructions_PL/SQL>
[EXCEPTIONS <traitement_exceptions>]
END;
Entête de bloc est défini quand il s'agit d'une fonction, procédure ou package
Sinon, le bloc reste anonyme
4
2
2 Structure d’un bloc PL/SQL
Exemple
Hi Everyone
3 Déclarations
Variables simples
CURSOR
DECLARE
dateEmbauche date;
nom varchar2(80) := ’Benali’;
trouve boolean;
incrSalaire constant number(3,2) := 1.5;
...
BEGIN
...
END;
6
3
3 Déclarations
DECLARE
maxSal employee.salary%TYPE;
employeeRec employee%ROWTYPE;
3 Déclarations
3.3 CURSOR
Le mot clé CURSOR sert à déclarer une zone mémoire qui recevra le résultat d'un
SELECT pour un parcours tuple par tuple
DECLARE
CURSOR empCursor IS
SELECT * FROM employee WHERE dept = 123;
DECLARE
CURSOR empCursor (dno number) IS
SELECT * FROM employee WHERE dept = dno;
4
3 Déclarations
Si un CURSOR est utilisé pour mettre à jour une ligne d'une table, on le signale avec
FOR UPDATE en fin de déclaration :
DECLARE
CURSOR empCursor IS
SELECT * FROM employee WHERE dept = 123
FOR UPDATE OF salary;
4 Instruction PL/SQL
PL/SQL permet tous les autres types de commandes SQL (e.g. INSERT, DELETE,
UPDATE, COMMIT).
La commande SELECT (sauf si imbriquée) est toujours utilisé avec INTO, pour
affecter les données retrouvées aux variables PL/SQL.
10
5
4 Instruction PL/SQL
4.1 Affectations
Affecter chaque tuple résultat d'un SELECT à une structure ou à une liste de
variable.
DECLARE
employeeRec employee%ROWTYPE;
BEGIN
SELECT *
INTO employeeRec
FROM employee
WHERE enum='E7';
dbms_output.putline(employeeRec.ename||‘ '||employeeRec.salary);
END;
11
4 Instruction PL/SQL
Une forme plus légère de la même requête consiste à accéder à des composants
bien définis :
DECLARE
employeeRec employee%ROWTYPE;
BEGIN
SELECT ename, salary
INTO employeeRec.ename, employeeRec.salary
FROM employee
WHERE enum = 'E8';
dbms_output.putline(employeeRec.ename||‘ '||employeeRec.salary);
END;
12
6
4 Instruction PL/SQL
4.2 Tests
13
4 Instruction PL/SQL
14
7
4 Instruction PL/SQL
4.3 Boucles
• WHILE - LOOP
• FOR - LOOP
• FOR IN
15
4 Instruction PL/SQL
4.3 Boucles
4.3.1 Boucle WHILE-LOOP
[<label_name>]
WHILE <condition> LOOP
<sequence_instructions>;
END LOOP [<label_name>];
On peut nommer une boucle pour, en cas de boucles imbriquées, s'y référer avec EXIT par
exemple.
8
4 Instruction PL/SQL
4.3 Boucles
4.3.2 Boucle FOR-LOOP
[<label_name>]
FOR <index> IN <lower_bound>..<upper_bound> LOOP
<séquence_instructions> ;
END LOOP [<label_name>];
BEGIN
FOR i IN 4..7 LOOP
dbms_output.put_line(i);
END LOOP ;
END;
17
4 Instruction PL/SQL
4.3 Boucles
4.3.3 Boucle LOOP- END LOOP
LOOP
<sequence_instructions>;
EXIT WHEN <condition>
END LOOP;
DECLARE
Compteur number := 0;
BEGIN
LOOP
compteur := compteur + 1;
EXIT WHEN compteur = 10;
END LOOP;
RETURN compteur;
END;
18
9
4 Instruction PL/SQL
4.3 Boucles
4.3.4 CURSOR avec WHILE
DECLARE
CURSOR empCursor IS SELECT * FROM EMPLOYEE;
employeeRec employee%ROWTYPE;
maxSal employee.salary%TYPE := 0;
BEGIN
OPEN empCursor;
/* Accès au premier tuple*/
FETCH empCursor INTO employeeRec;
WHILE empCursor%FOUND LOOP
/* traitement du tuple */
IF (maxSal < employeeRec.salary) THEN
maxSal := employeeRec.salary;
END IF;
/* Accès aux tuples suivants*/
FETCH empCursor INTO employeeRec;
END LOOP;
dbms_output.putline('Salaire Maximum: '|| maxsal);
CLOSE empCursor;
END; 19
4 Instruction PL/SQL
4.3 Boucles
4.3.4 CURSOR avec LOOP - END LOOP
DECLARE
CURSOR empCursor IS SELECT * FROM EMPLOYEE;
employeeRec employee%ROWTYPE;
maxSal employee.salary%TYPE := 0;
BEGIN
OPEN empCursor;
LOOP
/* Accès à chacun des tuples */
FETCH empCursor INTO employeeRec;
EXIT WHEN empCursor%NOTFOUND;
/* traitement du tuple */
IF (maxSal < employeeRec.salary) THEN
maxSal := employeeRec.salary;
END IF;
/* fin traitement tuple */
END LOOP ;
dbms_output.putline('Salaire Maximum: '|| maxsal);
CLOSE empCursor;
END; 20
10
4 Instruction PL/SQL
4.3 Boucles
4.3.4 CURSOR avec FOR
DECLARE
CURSOR empCursor IS SELECT * FROM EMPLOYEE;
employeeRec employee%ROWTYPE;
maxSal employee.salary%TYPE := 0;
BEGIN
FOR employeeRec IN empCursor LOOP
/* traitement du tuple */
IF (maxSal < employeeRec.salary) THEN
maxSal := employeeRec.salary;
END IF;
/* fin traitement tuple */
END LOOP;
dbms_output.putline('Salaire Maximum: '|| maxsal);
END;
21
4 Instruction PL/SQL
4.3 Boucles
4.3.5 Boucle FOR IN
BEGIN
FOR untel IN (SELECT * FROM employee)
LOOP
dbms_output.putline('Num = '||untel.enum ||', Nom = '||
untel.ename ||', Salaire = '||untel.salary);
END LOOP;
END;
22
11
4 Instruction PL/SQL
4.3 CURSOR avec mise à jour
Les commandes SQL UPDATE et DELETE peuvent être utilisés avec un CURSOR
(déclaré avec la clause FOR UPDATE OF)
DECLARE
CURSOR empCur is SELECT salary FROM employee
WHERE DEPT = 'D1' FOR UPDATE OF salary;
BEGIN
FOR empRec IN empCur LOOP
UPDATE employee
SET salary = empRec.salary * 1.05
WHERE current of empCur;
END LOOP;
COMMIT;
END;
23
[<entete_du_bloc>]
[DECLARE
<constantes>
<variables>
<cursors>
<exceptions_utilisateurs>]
BEGIN
<instructions_PL/SQL>
[EXCEPTIONS <traitement_exceptions>]
END;
24
12
5 Traitement des exceptions
BEGIN
<instructions_PL/SQL>
EXCEPTIONS
WHEN <nom_exception_1> THEN <sequence_instructions_1>;
WHEN <nom_exception_2> THEN <sequence_instructions_2>;
. . .
END;
RAISE <nom_exception>
25
CURSOR_ALREADY_OPEN
tentative d'ouverture de CURSOR déjà ouvert
INVALID_CURSOR
par exemple FETCH sur un CURSOR déjà fermé
NO_DATA_FOUND
aucun tuple retourné (SELECT INTO ou FETCH)
13
5 Traitement des exceptions
5.1 Exceptions systèmes (suite)
Une requête SELECT monotuple avec si un seul tuple retrouvé OK, sinon exception
DECLARE
employeeRec employee%ROWTYPE;
BEGIN
--noms et salaires d'employés d'un département donné--
SELECT ename, salary INTO employeeRec.ename, employeeRec.Salary
FROM EMPLOYEE
WHERE dept = '&dnum'; -- à lire avant --
dbms_output.putline(employeeRec.ename||‘ '||employeeRec.Salary);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.putline('Trop d employés!');
END;
27
DECLARE
sal employee.salary%TYPE;
num employee.enum%TYPE;
tropGrand exception;
CURSOR empCurseur is SELECT enum, salary FROM EMPLOYEE
WHERE DEPT = '&dept‘ FOR UPDATE OF SALary;
BEGIN
OPEN empCurseur;
LOOP
FETCH empCurseur INTO num, sal;
EXIT WHEN empCurseur%NOTFOUND;
IF sal * 1.05 > 4000 THEN RAISE tropGrand;
ELSE
UPDATE EMPLOYEE SAT salary = sal * 1.05
WHERE CURRENT OF empCurseur;
dbms_output.put_line (num || ' mis à jour.');
END IF;
END LOOP;
28
14
5 Traitement des exceptions
5.3 Exemple (suite)
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.putline('pas trouve');
WHEN tropGrand THEN
INSERT INTO veterans VALUES (num, sal);
dbms_output.putline(num||' '||Sal ||‘ Trop grand');
END;
29
6 Procédures et fonctions
Le plus souvent on crée plutôt une procédure ou une fonction nommée pour
réutiliser le code
Les fonctions peuvent aussi être utilisées dans les requêtes SQL
30
15
6 Procédures et fonctions
6.1 Procédure
31
6 Procédures et fonctions
Passage de paramètres
Dans la définition d’une procédure on indique le type de passage que l’on veut pour les
paramètres :
• OUT pour le passage par référence mais pour un paramètre dont la valeur n’est pas
utilisée en entrée
32
16
6 Procédures et fonctions
6.1 Procédure (suite 2)
Exemple 1 Une procédure qui calcule le carré d'un nombre avec paramètre IN
A l’exécution :
Un paramètre IN est pris comme une donnée et ne doit pas être modifié dans la
procédure (i.e., passage par valeur)
33
6 Procédures et fonctions
6.1 Procédure (suite 3)
Exemple 2 une procédure qui retourne le maximum de deux nombre avec le paramètre OUT
DECLARE
a NUMBER;
PROCEDURE max (a IN NUMBER, b IN NUMBER, x OUT NUMBER) IS
BEGIN
IF a>b THEN
x := a;
ELSE
x:=b; Paramètre x est passé
END IF;
END; par référence
BEGIN
max(2,5,a);
dbms_output.put_line('max = '||a);
END;
/
A l’exécution :
max = 5
Noter sur cet exemple que la procédure max a été déclarée à l'intérieur d'un bloc PL/SQL
dans la zone DECLARE 34
17
6 Procédures et fonctions
6.1 Procédure (suite 4)
Exemple 3
35
6 Procédures et fonctions
6.1 Procédure (suite 4)
Exemple 3 (suite)
Programme test : on augmente le salaire des employés gagnant moins qu'un montant
DECLARE
CURSOR empCursor IS SELECT * FROM EMPLOYEE;
minSal employee.SALary%TYPE := &smic;
BEGIN
FOR employeeRec IN empCursor LOOP
IF employeeRec.salary < minSal THEN
augmenterSalaire (employeeRec.enum, 10) ;
END IF;
END LOOP;
END;
/
36
18
6 Procédures et fonctions
6.2 Fonction
Sont semblables aux procédures, mais retournent une valeur résultat. Une fonction diffère
d'une procédure par le fait qu'on peut l'utiliser dans une expression.
Exemple
37
19