Vous êtes sur la page 1sur 19

Université Mouloud Mammeri de Tizi-Ouzou

Département de Génie Informatique

Cours III
Introduction au PL/SQL

Chargé de cours :
Saïd TALBI

Plan Cours III

1 Introduction

2 Structure d’un bloc PL/SQL

3 Déclarations

4 Instructions PL/SQL

5 Traitement des exceptions

6 Procédures et fonctions

1
1 Introduction

PL/SQL est un langage procédural (Procedural Language/SQL) qui permet en plus


de SQL d'avoir une structure algorithmique

L'unité de programmation en PL/SQL est le bloc

Un bloc contient des déclarations de variables et/ou de constantes et des


instructions (qui peuvent être des commandes SQL)

Parmi les instructions d'un bloc PL/SQL :


• Commandes SQL
• Instructions conditionnelles (IF-THEN-ELSE )
• Instructions de boucle (LOOP)
• Traitement des exceptions

Un bloc PL/SQL peut-être une fonction ou une procédure

PL/SQL permet de traiter le résultat d'une requête tuple par tuple. La notion de
CURSOR sert à cet effet
3

2 Structure d’un bloc PL/SQL

Un Bloc est constitué par :


• Partie déclarations (optionnelle)
• Partie instructions
• Partie de traitement d'exceptions (optionnelle)

[<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

Un bloc PL/SQL affichant le message "Hi Everyone" sous SQLPlus

SQL> SET SERVEROUTPUT ON


SQL> BEGIN
2 dbms_output.putline('Hi Everyone');
3 END;
4 /

Hi Everyone

3 Déclarations

Variables simples

Déclarations Variables références à la base

CURSOR

3.1 Variables simples

DECLARE
dateEmbauche date;
nom varchar2(80) := ’Benali’;
trouve boolean;
incrSalaire constant number(3,2) := 1.5;
...
BEGIN
...
END;
6

3
3 Déclarations

3.2 Variables par référence à la base de données

DECLARE
maxSal employee.salary%TYPE;
employeeRec employee%ROWTYPE;

• La première déclaration est de type colonne. La variable maxSal est une


variable PL/SQL de même type que la colonne salary de la table employee.

• La seconde déclaration est de type ligne. La variable employeeRec possède la


même structure (i.e., schéma) que la table employee.

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;

 Ou bien avec des paramètres formels

DECLARE
CURSOR empCursor (dno number) IS
SELECT * FROM employee WHERE dept = dno;

Le paramètre dno sera passé lors de l'ouverture avec OPEN :

OPEN empCursor (123);

4
3 Déclarations

3.3 CURSOR (suite)

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 les instructions des langages de programmation :


• Affectations
• Tests
• Boucles

 PL/SQL ne permet pas les commandes SQL de langage de définition comme la


création de table, la modification d'attribut etc.

 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

4.1 Affectations (suite)

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;

Le résultat est récupéré directement dans les champs de employeeRec

12

6
4 Instruction PL/SQL

4.2 Tests

Sémantiquement, cette structure est analogue aux autres langages procéduraux

IF <condition> THEN <sequence_instructions>


[ELSIF <condition> THEN <sequence_instructions>]
. . .
[ELSE <sequence_instructions>]
END IF;

La clause ELSIF poursuit le test et la clause END IF termine les tests.

13

4 Instruction PL/SQL

4.2 Tests (exemple)

DECLARE choix number;


BEGIN
IF choix = 1 THEN
DELETE
FROM employee
WHERE enum = 'E1';
ELSIF choix = 2 THEN
DELETE
FROM employee
WHERE enum = 'E2';
ELSE
DELETE
FROM employee
WHERE enum = 'E3';
END IF;
END;

14

7
4 Instruction PL/SQL
4.3 Boucles

• WHILE - LOOP

• FOR - LOOP

• LOOP - END LOOP

• Boucle avec CURSOR

• 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.

set serveroutput ON;


DECLARE
i number := 1;
BEGIN
WHILE i < 10 LOOP
i:= i+1;
dbms_output.put_line (TO_CHAR(i));
END LOOP;
END; 16

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>];

Conversion des nombre 1..9 en caractères et affichage des résultats :

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;

Compteur qui compte jusqu’à 10 :

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

Variante de la boucle FOR plus abstraite et utilisant une requête directe et un


CURSOR implicite

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)

Elles affectent alors seulement le tuple courant de FETCH. La clause WHERE


CURRENT OF CURSOR, est alors ajoutée à la commande.

Augmenter le salaire des employés du département D1 de 5%

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

5 Traitement des exceptions

 Une erreur ou avertissement PL/SQL peut survenir en cours d'exécution et


soulever une exception.

 Peut être prédéfinie par :


• Oracle (système)
• Déclaration par l'utilisateur

[<entete_du_bloc>]
[DECLARE
<constantes>
<variables>
<cursors>
<exceptions_utilisateurs>]
BEGIN
<instructions_PL/SQL>
[EXCEPTIONS <traitement_exceptions>]
END;

24

12
5 Traitement des exceptions

 Traitement d'une exception se fait par la règle WHEN comme suit:

BEGIN
<instructions_PL/SQL>

EXCEPTIONS
WHEN <nom_exception_1> THEN <sequence_instructions_1>;
WHEN <nom_exception_2> THEN <sequence_instructions_2>;
. . .
END;

Ici, la séquence d'instructions est exécutée quand l'exception donnée est


soulevée par la règle RAISE dans la partie instructions_PL/SQL :

RAISE <nom_exception>

25

5 Traitement des exceptions


5.1 Exceptions systèmes
Sont automatiquement soulevées lors de l'apparition de l'erreur ou de
l'avertissement correspondant

 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)

 TOO_MANY_ROWS: SELECT INTO


retourne plus d'un tuple
...
 ZERO_DIVIDE
tentative de division par zéro
26

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

5 Traitement des exceptions


5.2 Exemple
Augmenter de 5% les salaires des employés du département '123' sans toutefois dépasser 4000
(rajouter l'employé dans une table RICHE)

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)

Augmenter de 5% les salaires des employés du département '123' sans toutefois


dépasser 4000 (rajouter l'employé dans une table RICHE)

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

 Les procédures et fonctions peuvent être utilisées dans d’autres procédures ou


fonctions ou dans des blocs PL/SQL anonymes.

 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

Est un bloc nommé, éventuellement paramétré, qu'on peut exécuter à la demande

CREATE OR REPLACE PROCEDURE <nom_procedure> [(list_parametres)]


IS
[declaration_variables]
BEGIN
<code_procedure>
END;

 Pas de DECLARE, les variables sont déclarées entre IS et BEGIN

 Si la procédure ne nécessite aucune déclaration, le code est précédé par IS


BEGIN

31

6 Procédures et fonctions

6.1 Procédure (suite 1)

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 :

• IN pour le passage par valeur

• IN OUT pour le passage par référence

• 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

CREATE OR REPLACE PROCEDURE carre (a IN NUMBER)


IS
BEGIN
dbms_output.put_line('Carré = '||a*a);
END;
/
Procedure created.

A l’exécution :

SQL> execute carre(5)


Carré = 25

PL/SQL procedure successfully completed

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

PL/SQL procedure successfully completed

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

Augmentation de salaire d'un employé donné avec un taux donné

CREATE OR REPLACE PROCEDURE augmenterSalaire(pEnum in employee.enum%type,


tx IN NUMBER) IS
BEGIN
-- Mise à jour salaire employé
UPDATE employee
SET salary = salary + salary * tx / 100
WHERE enum = pEnum;
END;

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

Fonction qui convertit un montant en Euro vers un montant en Dinars

CREATE OR REPLACE FUNCTION toEuro(montant IN NUMBER) RETURN NUMBER


IS
BEGIN
RETURN montant/209;
END

Pour les fonctions, seul le passage par valeur IN est autorisé

37

19