Le Langage PL/SQL de Oracle (Brève Introduction)

Najib Tounsi

Sommaire

  1. Introduction
  2. Introduction (suite)
  3. Introduction (suite)
  4. Introduction (suite)
  5. Structure des blocs PL/SQL
  6. Structure des blocs PL/SQL (suite)
  7. L'inévitable "Hello world"
  8. Exemple de Programme
  9. Déclarations de variables
  10. Déclaration de variable par référence aux données de la base
  11. Déclarations de zone cursor
  12. Instructions
  13. Exemple d'interrogation SELECT mono-tuple
  14. Exemple d'interrogation Select mono-tuple (suite)
  15. Structure de contrôle if-then-else
  16. Structures de contrôles (boucle LOOP )
  17. Structures de contrôles (boucle LOOP )
  18. Structures de contrôles (boucle LOOP )
  19. Structures de contrôles (boucle LOOP  avec cursor)
  20. Même exemple avec WHILE ...
  21. Boucle pour chaque: FOR ... IN...
  22. Boucle pour chaque: FOR ... IN...
  23. Variante de boucle FOR ...in...
  24. Cursor donné lors de OPEN.
  25. Cursor avec mise à jour
  26. Traitement d'exceptions
  27. Traitement d'exceptions (suite)
  28. Exemple complet
  29. Procédures et fonctions
  30. Les Déclencheurs (Triggers)
  31. En savoir plus

Introduction

Introduction (suite)

Introduction (suite)

Introduction (suite)

Structure des blocs PL/SQL

Structure des blocs PL/SQL (suite)

[<Enête de bloc>] 
[DECLARE
<Constantes>
<Variables>
<Cursors>
<Exceptions utilisateurs>]
BEGIN
<Instruction PL/SQL>
[EXCEPTION <Traitement d'exception>]
END;

L'inévitable "Hello world"

SQL>   SET SERVEROUTPUT ON
SQL> BEGIN
2 dbms_output.put_line('Bonjour');
3 END;

4 /

Bonjour

Exemple de Programme

DECLARE
-- Partie optionnelle
 vEname employee.ename%TYPE; vSalary employee.Salary%TYPE;

BEGIN
-- Partie obligatoire
 SELECT ename , salary INTO vEname , vSalary FROM employee WHERE enum = ’E2’; DBMS_OUTPUT.PUT_LINE('Nom = ' || vEname ); DBMS_OUTPUT.PUT_LINE('Salaire = ' || vSalary); EXCEPTION
-- Partie optionnelle WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Erreur : ' || TO_CHAR(sqlcode)); DBMS_OUTPUT.PUT_LINE('Erreur : ' || sqlerrm); END; /

Déclarations de variables

DECLARE
dateEmbauche date; /* initialisation implicite avec null */
nom varchar2(80) := ’Benali’;
trouve boolean; /* initialisation implicite avec null aussi*/
incrSalaire constant number(3,2) := 1.5; /* constante */
. . .
BEGIN . . . END;

Déclaration de variable par référence aux données de la base

NB. Les exemples dans la suite portent sur la table :

Employee (enum, ename, salary, address, dept)

Variable de type colonne

DECLARE
maxSal employee.salary%TYPE;

Variable de type ligne

DECLARE
employeeRec employee%ROWTYPE;

Déclarations de zone cursor

DECLARE
CURSOR empCursor IS
SELECT * FROM employee WHERE dept = 123
DECLARE
CURSOR empCursor (dno number ) IS
SELECT * FROM employee WHERE dept = dno;
OPEN empCursor (123);
DECLARE
CURSOR empCursor IS
SELECT * FROM employee WHERE dept = 123
FOR UPDATE OF salary;

Instructions

DECLARE
quantite integer := 0;
...
BEGIN
quantite := quantite + 5;
...
END

Exemple d'interrogation SELECT mono-tuple

DECLARE
 employeeRec employee%ROWTYPE;
maxSal employee.salary%TYPE;
BEGIN
SELECT * INTO employeeRec
FROM employee WHERE enum='E7';
dbms_output.put_line(employeeRec.ename||' '||employeeRec.Salary);
END;

Exemple d'interrogation Select mono-tuple (suite)

BEGIN 
SELECT ename, salary INTO employeeRec.ename, employeeRec.Salary
FROM employee

WHERE enum = 'E8';

dbms_output.put_line(employeeRec.ename||' '||employeeRec.Salary);
END;
BEGIN
SELECT max(salary) INTO maxSal
FROM employee;
dbms_output.put_line('Salaire Maximum: '|| maxsal);
END;

Structure de contrôle if-then-else 

IF <condition> THEN   <séquence d'instructions> 
[ELSIF <condition> THEN <séquence d'instructions> ]
. . .
[ELSE <séquence d'instructions> ]
END IF ;

Structures de contrôles (boucle LOOP )

[<label>] 
WHILE <condition> LOOP
<séquence d'instructions>;
END LOOP [<label>] ;
DECLARE
i number;
BEGIN
i:=0;
WHILE i<8 LOOP
dbms_output.put_line(i);
i:= i+1;
END LOOP ;
END;

Structures de contrôles (boucle LOOP )

[<label name>]
FOR <index> IN [reverse] <lower bound>..<upper bound> LOOP
<séquence d'instructions> ;
END LOOP [<label name>] ;
BEGIN
FOR i IN 4..7 LOOP
dbms_output.put_line(i);
END LOOP ;
END;

Structures de contrôles (boucle LOOP )

LOOP  ... END LOOP ;
EXIT WHEN ...

Structures de contrôles (boucle LOOP  avec cursor)

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.put_line('Salaire Maximum: '|| maxsal);
CLOSE empCursor;
END;

Même exemple avec WHILE ...

Usage se %FOUND, pour boucler. Mêmes déclarations.


BEGIN 
OPEN empCursor;
FETCH empCursor INTO employeeRec;

WHILE empCursor%FOUND LOOP

/* traitement du tuple */
IF maxSal < employeeRec.salary THEN
maxSal := employeeRec.salary;
END IF;
/* fin traitement tuple */

FETCH empCursor INTO employeeRec;
END LOOP ;

dbms_output.put_line('Salaire Maximum: '|| maxsal);
CLOSE empCursor;
END;

Boucle pour chaque: FOR ... IN...

Boucle pour chaque: FOR ... IN...

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.put_line('Salaire Maximum: '|| maxsal);
END;

Variante de boucle FOR ...in...

BEGIN
FOR untel IN (SELECT * FROM employee )
LOOP
dbms_output.put_line('Num = ' || untel.enum ||
', Nom = ' || untel.ename ||
', Salaire = '|| untel.salary);
END LOOP;
END;
FOR salVar IN  (SELECT salary * 1.07 nouveau FROM employee) LOOP  
/* ... */
END LOOP ;

Cursor donné lors de OPEN.

Usage du mot clé TYPE avec REF CURORSOR.

Declare
-- le curseur
TYPE EmpCurType IS REF CURSOR;
empCur EmpCurType;
-- les variables
nom employee.ename%TYPE ;
Begin
OPEN empCur FOR 'SELECT ename FROM employee' ;
FETCH empCur INTO nom ; -- On FETCH le premier...
dbms_output.put_line( nom ) ;
CLOSE empCur;
End ;

Cursor avec mise à jour

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;

Traitement d'exceptions

WHEN <nom d'exception> THEN   <séquence  d'instructions>; 
DECLARE
employeeRec employee%ROWTYPE;
BEGIN
-- chercher les 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.put_line(employeeRec.ename||' '||employeeRec.Salary);

EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('Trop d employés.');
END;

Traitement d'exceptions (suite)

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
WHEN NO DATA FOUND THEN   rollback;
RAISE <nom d'exception>

Exemple complet

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 a jour.');
END IF ;
END LOOP ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('pas trouve');
rollback;
WHEN tropgrand THEN
INSERT INTO veterans VALUES (num, sal);
dbms_output.put_line(num||' '||Sal || ' Trop grand');
COMMIT;
END;

Voir aussi PL/SQL par l'exemple.

Procédures et fonctions

Les Déclencheurs (Triggers)

En savoir plus