Vous êtes sur la page 1sur 19

PL/SQL (#1)

Dfinition (1)

Instructions de base
Squences, curseurs
Traitement des erreurs
Procdures et fonctions
Tableaux, structures et collections






PL/SQL = Procedural Language / SQL


Extension du langage SQL
Langage de programmation procdural (L3G)
Intgr dans Oracle (SQL+, PRO*C,SQL*FORMS )

 Possibilits:
 Ordres SQL (LMD): SELECT,INSERT,UPDATE,DELETE
 Variables et sous-programmes (BLOC PL/SQL)
 Structures conditionnelles: IF,THEN,ELSEIF,ELSE,ENDIF
 Structures itratives : LOOP,FOR,WHILE,EXIT WHEN
 Utilisation des fonctions et prdicats SQL

JeanJean-Luc GOERIG - plsql_bases.pdf - #090915 - rvision septembre 2009

1/76

PL/SQL (#1)

Jean-Luc GOERIG

2/76

PL/SQL (#1)

Jean-Luc GOERIG

Dfinition (2)

Une structure de Blocs

 Possibilits:
 Gestion de curseurs
 Traitement des erreurs : EXCEPTION
 Gestion de transactions: COMMIT,ROLLBACK,SAVEPOINT
 Procdures et fonctions: CREATE PROCEDURE ou FUNCTION
 Packages: regroupement de procdures et fonctions
 Packages standards Oracle (DBMS_OUTPUT,UTL_FILE )
 Codage de Triggers
 Restriction:
 LDD impossible (ALTER,CREATE.)
 Avantages:
 Portabilit sur Oracle, performant, facilit de programmation

 PL/SQL interprte un ensemble de commandes contenu dans un


programme ou bloc PL/SQL:
DECLARE
DECLARE
-- Section facultative
-- Section facultative
--- Dclarations:variables
Dclarations:variables locales
locales au
au bloc
bloc
constantes, exceptions
constantes, exceptions
curseurs
curseurs
BEGIN
BEGIN
-- Section obligatoire contenant les commandes excutables
-- Section obligatoire contenant les commandes excutables
--- Instructions
Instructions SQL
SQL et
et PL/SQL
PL/SQL
--- Imbrication
Imbrication de
de blocs:
blocs:
BEGIN
BEGIN - bloc
bloc BB

END;
END; --- fin
fin bloc
bloc BB
EXCEPTION
EXCEPTION
--- Section
Section facultative
facultative
--- Traitement
Traitement des
des exceptions
exceptions (gestion
(gestion des
des erreurs)
erreurs)
END;
END;

 Chaque instruction de nimporte quelle section doit se terminer par un ;


3/76

PL/SQL (#1)

Jean-Luc GOERIG

4/76

PL/SQL (#1)

Jean-Luc GOERIG

Exemple

Variables (1)

--- traitement
traitement de
de commandes
commandes
DECLARE
DECLARE
qte_stock
qte_stock number(5);
number(5);
BEGIN
BEGIN
Select
Select quantite
quantite into
into qte_stock
qte_stock
from
inventaire
from inventaire
where
where produit=chaise;
produit=chaise;
--- contrle
contrle du
du stock
stock suffisant
suffisant
if
if qte_stock
qte_stock >> 00 then
then
update
update inventaire
inventaire set
set quantite
quantite == quantite
quantite 11
where
where produit=chaise;
produit=chaise;
insert
insert into
into achat
achat
values
values (chaise,sysdate);
(chaise,sysdate);
else
else
insert
insert into
into acheter
acheter
values
values (Plus
(Plus de
de chaise!,sysdate);
chaise!,sysdate);
end
end if;
if;
commit;
commit;
END;
END;

5/76

PL/SQL (#1)

 Types de variables:
 variables locales:

type natif Oracle (NUMBER,CHAR)


type boolen (valeurs TRUE,FALSE, NULL)
faisant rfrence au D. de Donnes Oracle
variables SQL*Plus (&)

 variables externes:

Host variables (langage hte avec :)


variables dcrans SQL*Forms
 Dclaration des variables:
 les variables locales sont dfinies dans la section DECLARE

 Variables de type Oracle:


DECLARE
DECLARE
nom char(15);
nom char(15);
numero_truc number;
-- longueur 38
numero_truc number;
-- longueur 38
date_jour date;
date_jour date;
salaire
number(7,2);
salaire
number(7,2);
BEGIN
BEGIN

Jean-Luc GOERIG

6/76

PL/SQL (#1)

Jean-Luc GOERIG

Variables (2)

Variables (3)

 Variables de type boolen:

 Variables de mme type quune variable prcdemment dfinie:

DECLARE
DECLARE
reponse
reponse boolean;-boolean;-- valeur
valeur TRUE,FALSE,NULL
TRUE,FALSE,NULL
BEGIN
BEGIN

 Variables faisant rfrence au D.D. Oracle (%TYPE):


 variables hritant du mme type quune colonne de table
 permet de rpercuter des modifications de structure dune table
DECLARE
DECLARE
nom
nom
BEGIN
BEGIN

emp.name%TYPE;
emp.name%TYPE;

 Visibilit et initialisation des variables:


 Une variable est visible dans le bloc o elle a t dclare
et dans les blocs imbriqus si elle na pas t redfinie
 oprateur daffectation :=

-- de mme type que la colonne NAME de la table EMP


-- de mme type que la colonne NAME de la table EMP

 variable reprenant la structure quune ligne dune table (%ROWTYPE)


DECLARE
DECLARE
enreg emp%ROWTYPE; -- chaque champ de la variable ENREG a mme nom et mme type
enreg emp%ROWTYPE; -- chaque champ de la variable ENREG a mme nom et mme type
--- que
que la
la colonne
colonne associe:
associe: enreg.nomcolonne
enreg.nomcolonne
BEGIN
BEGIN

7/76

DECLARE
DECLARE
commission
commission number(7,2);
number(7,2);
salaire
salaire commission%TYPE;
commission%TYPE;
BEGIN
BEGIN

PL/SQL (#1)

Jean-Luc GOERIG

DECLARE
DECLARE
nom
nom char(10)
char(10) :=
:= Zorro;
Zorro;
salaire
salaire number(7,2)
number(7,2) :=
:= 9800;
9800;
reponse
boolean
:=
TRUE;
reponse boolean := TRUE;
BEGIN
BEGIN

8/76

PL/SQL (#1)

Jean-Luc GOERIG

Variables (4)

Structures conditionnelles
 Trois formes de IF:

 Ordre SELECT INTO (section BEGIN)


DECLARE
DECLARE
nom_emp
nom_emp CHAR(15);
CHAR(15);
sal
sal emp.salaire%TYPE;
emp.salaire%TYPE;
com
com emp.commission%TYPE;
emp.commission%TYPE;
nom_serv
nom_serv CHAR(15);
CHAR(15);
BEGIN
BEGIN
SELECT
SELECT nom,salaire,commission,service
nom,salaire,commission,service
INTO
INTO nom_emp,sal,com,nom_serv
nom_emp,sal,com,nom_serv
FROM
FROM emp,serv
emp,serv
WHERE
WHERE nom='dupont'
nom='dupont'
AND
AND emp.noserv=serv.noserv;
emp.noserv=serv.noserv;

IF
IF <condition>
<condition> THEN
THEN
traitement;
traitement;
END
END IF;
IF;

 Clause into obligatoire!


 Le select ne doit ramener quune seule ligne! (sinon programmer un curseur)

PL/SQL (#1)

Jean-Luc GOERIG

CASE
<variable>
CASE
<variable>
WHEN
WHEN <condition1>
<condition1> THEN
THEN instructions1;
instructions1;
WHEN
WHEN <condition2>
<condition2> THEN
THEN instructions2;
instructions2;

WHEN
WHEN <conditionN>
<conditionN> THEN
THEN instructionsN;
instructionsN;
[[ ELSE
instructionsZ;
ELSE
instructionsZ; ]]
END
END CASE;
CASE;

Oprateurs valides: = <


10/76

> !=
is null

Structures itratives (2)

 4 types de boucle :
boucle de base LOOP
boucle FOR
 Boucle de base LOOP:

 Boucle FOR (pour):

instructions;
instructions;
END
END LOOP;
LOOP;

 sortie de la boucle par la commande EXIT [label] [when condition]

11/76

not
like
Jean-Luc GOERIG

la dclaration de la variable indice est implicite.


valeur_dbut, valeur_fin: constantes, expressions ou variables.
l'indice varie de valeur_dbut valeur_fin avec un incrment de 1.
avec l'option REVERSE le pas est de -1 de valeur_fin vers valeur_dbut.
DECLARE
DECLARE
fact
fact NUMBER:=1;
NUMBER:=1;
BEGIN
BEGIN
FOR i IN 1..9
FOR i IN 1..9
LOOP
LOOP
fact:=fact*i;
fact:=fact*i;
END LOOP;
END LOOP;
INSERT INTO resultat VALUES (fact,'factorielle 9');
INSERT INTO resultat VALUES (fact,'factorielle 9');
END;
END;

VALUES
VALUES (nbre);
(nbre);

PL/SQL (#1)

and
or
between

FOR
FOR var_indice
var_indice IN
IN [REVERSE]
[REVERSE] valeur_dbut
valeur_dbut ..
.. valeur_fin
valeur_fin
LOOP
LOOP
instructions;
instructions;
END
END LOOP;
LOOP;

boucle WHILE
boucle CURSOR...FOR

LOOP
LOOP

>= <=
is not null

PL/SQL (#1)

Structures itratives (boucles) (1)

DECLARE
DECLARE
nbre
nbre NUMBER:=1;
NUMBER:=1;
BEGIN
BEGIN
LOOP
LOOP
INSERT
INSERT INTO
INTO rsultat
rsultat
nbre:=nbre+1
nbre:=nbre+1
EXIT WHEN nbre > 10;
EXIT WHEN nbre > 10;
END LOOP;
END LOOP;
END;
END;

IF
IF <condition1>
<condition1> THEN
THEN
traitement1;
traitement1;
ELSIF
ELSIF <condition2>
<condition2> THEN
THEN
traitement2;
traitement2;
ELSE
ELSE
traitement3;
traitement3;
END
END IF;
IF;

 Structure CASE:

Attention!

9/76

IF
IF <condition>
<condition> THEN
THEN
traitement1;
traitement1;
ELSE
ELSE
traitement2
traitement2
END
END IF;
IF;

Jean-Luc GOERIG

12/76

PL/SQL (#1)

Jean-Luc GOERIG

Structures itratives (3)

Structures itratives (4)

 Boucle WHILE (Tq):

 Boucle Rpter:
 Dommage! il ny a pas de repeat en PL/SQL!
 Se programme avec la syntaxe LOOP EXIT.

BEGIN
BEGIN
WHILE
WHILE condition
condition
LOOP
LOOP
instructions;
instructions;
END
LOOP;
END LOOP;

BEGIN
BEGIN
...
...
LOOP
LOOP

END;
END;

<instructions>;
<instructions>;
EXIT
EXIT WHEN
WHEN <condition>;
<condition>;
END
LOOP;
END LOOP;
...
...

Excution de la boucle tant que la condition de la clause while est vrifie


DECLARE
DECLARE
reste NUMBER := 7324;
reste NUMBER := 7324;
BEGIN
BEGIN
WHILE
WHILE reste
reste >=
>= 99
LOOP
LOOP
reste
reste :=
:= reste
reste -- 9;
9;
END LOOP;
END LOOP;
INSERT INTO resultat VALUES (reste,reste de la division de 7324 par 9);
INSERT INTO resultat VALUES (reste,reste de la division de 7324 par 9);
END;
END;

13/76

PL/SQL (#1)

Jean-Luc GOERIG

14/76

PL/SQL (#1)

Jean-Luc GOERIG

Utilisation de variables dfinies sous SQL*Plus

Package DBMS_OUTPUT

 On peut dfinir des variables sous SQL*Plus par la commande ACCEPT


Ces variables sont utilisables dans le bloc PL/SQL en les prfixant par &
Ce sont des variables de substitution.

 Le package standard DBMS_OUTPUT :


 PL/SQL ne possde pas dinstructions natives permettant dafficher sous
SQL*PLUS le contenu des variables.
 Pour tracer lexcution dun bloc PL/SQL, il est commode dutiliser le
package DBMS_OUTPUT livr dorigine avec Oracle.
 Pour utiliser DBMS_OUTPUT dans SQL*Plus, passer la commande
<SET SERVEROUTPUT ON> avant lexcution du bloc PL/SQL.
 Dans Sql Developer, cest licne [Activer la sortie SGBD] qui active
<SERVEROUTPUT ON> dans la fentre [Sortie SGBD].
 Ne pas oublier linstruction DBMS_OUTPUT.ENABLE.

--- variables
variables SQL*Plus
SQL*Plus
accept
accept lenom
lenom prompt
prompt taper
taper votre
votre nom:
nom:
declare
declare
vnom
vnom char(15);
char(15);
vnompilote
vnompilote transair.pilote.nompil%type;
transair.pilote.nompil%type;
begin
begin
vnom
vnom :=
:= &lenom;
&lenom;
select
select nompil
nompil into
into vnompilote
vnompilote
from
from transair.pilote
transair.pilote
where
where nompil='&lenom';
nompil='&lenom';
...
...
end;
end;

NB: ces variables sont utilisables avec Sql Developer sans accept.
15/76

PL/SQL (#1)

Jean-Luc GOERIG

declare
declare
vnum
vnum transair.pilote.nopilote%type;
transair.pilote.nopilote%type;
vnom
vnom transair.pilote.nompil%type;
transair.pilote.nompil%type;
begin
begin
dbms_output.enable;
dbms_output.enable;
select
select nopilote,nompil
nopilote,nompil into
into vnum,vnom
vnum,vnom from
from transair.pilote
transair.pilote where
where nompilote
nompilote =6723;
=6723;
dbms_output.put_line('Pilote:
dbms_output.put_line('Pilote: '||vnum||'
'||vnum||' '||vnom);
'||vnom);
...
...
end;
end;

16/76

PL/SQL (#1)

Jean-Luc GOERIG

Mise en uvre de PL/SQL et dboguage + exercice

PL/SQL avec Sql Developer

 Programmer en PL/SQL sous SQL *Plus:







Saisir le code PL/SQL avec un diteur dans un script SQL


Excuter le script sous SQL*Plus avec la commende @
Dboguage du programme: commande show errors;
Afficher le code source:
select line,text from user_sources;

 Mieux: programmer avec Sql Developer ! (voir diapo suivante)


Exercice:
Exercice:
Ecrire
Ecrireun
unprogramme
programmePL/SQL
PL/SQLqui
quieffectue
effectuelalademande
demandelalaconversion
conversiondun
dunnombre
nombrede
desecondes
secondes
en
enheures,minutes
heures,minutesetetsecondes
secondesou
oulalaconversion
conversiondun
dunnombre
nombredheures,minutes
dheures,minutesetetsecondes
secondesen
en
nombre
de
secondes.
nombre de secondes.
exemple:
exemple:11heure
heure20
20min
min30
30sec
sec==4860
4860secondes
secondes
Utiliser
Utiliserpour
pourles
lescalculs
calculsles
lesfonctions
fonctionsOracle
Oraclesuivantes:
suivantes:
floor(nombre/diviseur)
floor(nombre/diviseur)pour
pourobtenir
obtenirlelersultat
rsultaten
enentier
entier
mod(nombre,diviseur)
mod(nombre,diviseur)pour
pourlelemodulo
modulo
Faire
Faireafficher
afficherles
lesrsultats
rsultatsavec
avecDBMS_OUTPUT
DBMS_OUTPUT

17/76

PL/SQL (#1)

Jean-Luc GOERIG

Complment: les squences (1)

CREATE
CREATE SEQUENCE
SEQUENCE [schma.]
[schma.] <nom_squence>
<nom_squence>
[[ INCREMENT
INCREMENT BY
BY << 11 || entier
entier >]
>]
[[ START
START WITH
WITH entier
entier ]]
[[ << MAXVALUE
MAXVALUE entier
entier || NOMAXVALUE
NOMAXVALUE >> ]]
[[ << MINVALUE
MINVALUE entier
entier || NOMINVALUE
NOMINVALUE >> ]]
[[ << CYCLE
CYCLE || NOCYCLE
NOCYCLE >> ]]
[[ << CACHE
CACHE entier
entier || NOCACHE
NOCACHE >> ]]
[[ << ORDER
|
NOORDER
ORDER | NOORDER >> ];
];

nom_squence
de donnes
INCREMENT
squence
START WITH

Jean-Luc GOERIG

nom enregistr dans le dictionnaire


pas d'incrmentation du numro de
valeur positive ou ngative
valeur de dpart de la squence
par dfaut: = MINVALUE pour squence

asc.
= MAXVALUE pour squence

Depuis Oracle 11g, il est possible dutiliser CURRVAL et NEXTVAL dans un bloc
PL/SQL. Les expressions <squence.CURRVAL> et <squence.NEXTVAL> peuvent
tre utilises tout endroit o une expression de type Number peut apparatre.

PL/SQL (#1)

PL/SQL (#1)

Squences (2)

 Utililit des squences:


 Gnrateur de valeurs squentielles (compteur), des valeurs de cl
primaire
 Trs utilis en PL/SQL
 Dfinition dune squence:
 Par l'ordre CREATE SEQUENCE:

19/76

18/76

Jean-Luc GOERIG

desc.
MAXVALUE
MINVALUE
20/76
NOMAXVALUE
NOMINVALUE

limites maximum ou minimum


de la squence
Jean-Luc
GOERIG
limites
dfaut
PL/SQL
(#1) hautes et basses par
E
(1 10 27-1 selon le sens asc. ou

Squences (3)

Squences (4)

 Exemple de cration et de suppression:


SQL> create sequence seqmachine
SQL> create sequence seqmachine
22 start
start with
with 1000
1000
33 increment
increment by
by 10
10
44 nomaxvalue
nomaxvalue
55 nocycle;
nocycle;
Squence
Squence cre.
cre.
SQL>
SQL> drop
drop sequence
sequence seqmachine;
seqmachine;
Squence
Squence supprime.
supprime.

 Mise en uvre:
 Utilisation d'une squence dans une ordre SQL (SELECT, INSERT, UPDATE)
en tant que pseudo-colonne par:
nom_squence.NEXTVAL (gnre la valeur suivante de la squence)
nom_squence.CURRVAL (donne la valeur courante de la squence)

21/76

PL/SQL (#1)

Jean-Luc GOERIG

SQL> create table machine


SQL> create table machine
22 (nomachine
(nomachine number(4)
number(4) primary
primary key,
key,
33 nommachine
nommachine varchar2(15),
varchar2(15),
44 typemachine
typemachine char(1));
char(1));
Table
Table cre.
cre.
SQL> insert into machine (nomachine,nommachine,typemachine)
SQL> insert into machine (nomachine,nommachine,typemachine)
2
values (seqmachine.nextval,'Vrombisseuse','X');
2
values (seqmachine.nextval,'Vrombisseuse','X');
1 ligne cre.
1 ligne cre.
SQL> insert into machine (nomachine,nommachine,typemachine)
SQL> insert into machine (nomachine,nommachine,typemachine)
2
values (seqmachine.nextval,'Trimeusse','Z');
2
values (seqmachine.nextval,'Trimeusse','Z');
1 ligne cre.
1 ligne cre.
SQL> select * from machine;
SQL> select * from machine;
NOMACHINE NOMMACHINE
T
NOMACHINE NOMMACHINE
T
----------------- ----------------------------- -1000 Vrombisseuse
X
1000 Vrombisseuse
X
1010
ZZ
1010 Trimeusse
Trimeusse
SQL> select seqmachine.currval from dual;
SQL> select seqmachine.currval from dual;
CURRVAL
CURRVAL
----------------1010
1010

22/76

PL/SQL (#1)

Squences (5)

Squences (6)

 Modification:

 Compteur alphanumrique:

 Modification possible de certains paramtres d'une squence

 Gnration automatique de valeurs alphanumriques pour cl primaire


SQL> select seqmachine.nextval from dual;
SQL> select seqmachine.nextval from dual;
NEXTVAL
NEXTVAL
----------------1030
1030
SQL>
SQL> select
select 'MA'||lpad(to_char(seqmachine.nextval),4,'0')
'MA'||lpad(to_char(seqmachine.nextval),4,'0') numro
numro
22 from
from dual;
dual;
NUMRO
NUMRO
----------MA1035
MA1035
SQL> select 'MA'||lpad(to_char(seqmachine.currval),4,'0') numro
SQL> select 'MA'||lpad(to_char(seqmachine.currval),4,'0') numro
2 from dual;
2 from dual;
NUMRO
NUMRO
----------MA1035
MA1035

ALTER SEQUENCE [schma.] nom_squence


ALTER SEQUENCE [schma.] nom_squence
[INCREMENT BY <1|valeur>]
[INCREMENT BY <1|valeur>]
[<MAXVALUE valeur | NOMAXVALUE>]
[<MAXVALUE valeur | NOMAXVALUE>]
[<MINVALUE
[<MINVALUE valeur
valeur || NOMINVALUE>]
NOMINVALUE>]
[<CYCLE
[<CYCLE || NOCYCLE>]
NOCYCLE>]
[<CACHE
valeur
|
20
|
[<CACHE valeur | 20 | NOCACHE>];
NOCACHE>];
SQL> alter sequence seqmachine
SQL> alter sequence seqmachine
2
increment by 5
2
increment by 5
33 maxvalue
maxvalue 5050
5050
4
cycle;
4
cycle;
Squence
modifie.
Squence modifie.
SQL> select * from user_sequences
SQL> select * from user_sequences
2 where sequence_name like 'SEQMACH%';
2 where sequence_name like 'SEQMACH%';
SEQUENCE_NAME
SEQUENCE_NAME MIN_VALUE
MIN_VALUE MAX_VALUE
MAX_VALUE INCREMENT_BY
INCREMENT_BY CC OO CACHE_SIZE
CACHE_SIZE LAST_NUMBER
LAST_NUMBER
--------------- --------- --------- ------------ - - ---------- ------------------------- --------- --------- ------------ - - ---------- ----------SEQMACHINE
1
5050
5 Y N
20
1015
SEQMACHINE
1
5050
5 Y N
20
1015

23/76

PL/SQL (#1)

Jean-Luc GOERIG

 Tout appel une squence par NEXTVAL dclenche l'incrmentation !

Jean-Luc GOERIG

24/76

PL/SQL (#1)

Jean-Luc GOERIG

Squences avec Sql Developer

Curseurs
 Un curseur est une zone de mmoire de taille fixe, utilise par le noyau
d'ORACLE pour analyser et interprter tout ordre SQL.
 Il existe deux types de curseurs :
 Curseur explicite (select ... into)
 Curseur implicite (for) pour simplifier lcriture. 

25/76

PL/SQL (#1)

Jean-Luc GOERIG

Etapes dun curseur explicite

26/76

PL/SQL (#1)

Jean-Luc GOERIG

Notes : algorithme de lecture dun fichier squentiel

 L'utilisation d'un curseur explicite ncessite 4 tapes :


1)Dclaration : DECLARE
CURSOR nom_curseur IS ordre select;
2)Ouverture : BEGIN
OPEN nom_curseur;
L'ouverture provoque l'allocation mmoire, l'analyse syntaxique et
smantique du select, le positionnement de verrous (si select ... for
update)
3)Traitement des lignes : FETCH nom_curseur INTO liste de variables;
La valeur de chaque colonne est stocke dans une variable rceptrice.
le fetch ramne une seule ligne la fois.
CLOSE nom_curseur;
4)Fermeture :
La place mmoire est libre la fermeture du curseur.

27/76

PL/SQL (#1)

Jean-Luc GOERIG

28/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseur explicite Tq

Attributs dun curseur (1)

 Exemple gnral (Tq):

 Ils indiquent l'tat (statut) du curseur :

-- prompt curseur explicite version1 while + %found


-- prompt curseur explicite version1 while + %found
-- drop table liste;
-- drop table liste;
-- create table liste (col1 char(20),col2 char(20),col3 char(20));
-- create table liste (col1 char(20),col2 char(20),col3 char(20));
declare
declare
cursor cv1 is
cursor cv1 is
select
select nom_emp,service,
nom_emp,service, nom_serv
nom_serv
from emp,service where service=num_serv;
from emp,service where service=num_serv;
vnom
vnom emp.nom_emp%type;
emp.nom_emp%type;
vnumserv
vnumserv emp.service%type;
emp.service%type;
vservice
vservice service.nom_serv%type;
service.nom_serv%type;
begin
begin
open
cv1;
open cv1;
fetch
fetch cv1
cv1 into
into vnom,
vnom, vnumserv,
vnumserv, vservice;
vservice;
while
while cv1%found
cv1%found
loop
loop
insert into liste values(vnom,vnumserv,vservice);
insert into liste values(vnom,vnumserv,vservice);
fetch cv1 into vnom, vnumserv, vservice;
fetch cv1 into vnom, vnumserv, vservice;
end loop;
end loop;
close cv1;
close cv1;
end;
end;
--- select
select ** from
from liste;
liste;

29/76

PL/SQL (#1)

%FOUND %NOTFOUND %ISOPEN

%ROWCOUNT

 %FOUND :
type boolen
SQL%FOUND (curseur implicite) ou nom_curseur%FOUND
TRUE si une ligne au moins est traite ou ramene.
 %NOTFOUND : type boolen
SQL%NOTFOUND ou nom_curseur%NOTFOUND
TRUE si aucune ligne n'est traite ou ramene.

Jean-Luc GOERIG

Attributs dun curseur (2)

30/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseur avec Sql Developer

 %ISOPEN :
type boolen
SQL%ISOPEN est toujours FALSE
nom_curseur%ISOPEN est TRUE lorsque le curseur est ouvert.
 %ROWCOUNT : type numerique
SQL%ROWCOUNT contient le nombre de lignes traites (I,U,D)
avec 0 : le select into ne ramne aucune ligne
1 : le select into ramne 1 ligne
2 : le select into ramne plus d'1 ligne
nom_curseur%ROWCOUNT traduit la nime ligne ramene par le
fetch.

31/76

PL/SQL (#1)

Jean-Luc GOERIG

32/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseur explicite avec loop

Curseur FOR

prompt curseur explicite version2 loop et %notfound


prompt curseur explicite version2 loop et %notfound
drop table liste;
drop table liste;
create table liste (col1 char(20),col2 char(20),col3 char(20));
create table liste (col1 char(20),col2 char(20),col3 char(20));
declare
declare
cursor cv2 is
cursor cv2 is
select nom_emp,service, nom_serv
select nom_emp,service, nom_serv
from emp,service
where service=num_serv;
from emp,service
where service=num_serv;
vnom emp.nom_emp%type;
vnom emp.nom_emp%type;
vnumserv emp.service%type;
vnumserv emp.service%type;
vservice service.nom_serv%type;
vservice service.nom_serv%type;
begin
begin
open cv2;
open cv2;
loop
loop
fetch cv2 into vnom, vnumserv, vservice;
fetch cv2 into vnom, vnumserv, vservice;
exit when cv2%notfound;
exit when cv2%notfound;
insert
insert into
into liste
liste values(vnom,vnumserv,vservice);
values(vnom,vnumserv,vservice);
end loop;
end loop;
close cv2;
close cv2;
commit;
commit;
end;
/
end;
/
select * from liste;
select * from liste;

 Curseur avec boucle FOR: 

33/76

PL/SQL (#1)

PROMPT nombre de salaires ?


PROMPT nombre de salaires ?
ACCEPT
ACCEPT nombre
nombre
drop
drop table
table rsultat;
rsultat;
create
create table
table rsultat
rsultat (col1
(col1 char(20),col2
char(20),col2 char(20))
char(20))
//
DECLARE
DECLARE
CURSOR
CURSOR cv3
cv3 IS
IS SELECT
SELECT nom_emp,salaire
nom_emp,salaire
FROM
FROM emp
emp ORDER
ORDER BY
BY salaire
salaire DESC;
DESC;
vnom
emp.nom_emp%TYPE;
vnom emp.nom_emp%TYPE;
vsal
emp.salaire%TYPE;
vsal emp.salaire%TYPE;
BEGIN
BEGIN
OPEN
OPEN cv3;
cv3;
FOR
FOR ii IN
IN 1..&nombre
1..&nombre
LOOP
LOOP
FETCH
FETCH cv3
cv3 INTO
INTO vnom,vsal;
vnom,vsal;
INSERT
INSERT INTO
INTO rsultat
rsultat VALUES
VALUES (vnom,vsal);
(vnom,vsal);
END
LOOP;
END LOOP;
CLOSE
cv3;
CLOSE cv3;
END;
END;
//

Jean-Luc GOERIG

Curseurs implicites (1)

34/76

DECLARE
CURSOR nom_curseur is ordre select;
nom_structure nom_curseur%ROWTYPE;
BEGIN

 Forme condense utilisant la boucle FOR:


DECLARE
CURSOR nom_curseur IS ordre select ;
BEGIN
FOR nom_structure IN nom_curseur
LOOP
-traitements
END LOOP;
prompt curseur version1 implicite forme condense
prompt curseur version1 implicite forme condense
drop table liste;
drop table liste;
create table liste (col1 char(20),col2 char(20),col3 char(20));
create table liste (col1 char(20),col2 char(20),col3 char(20));
declare
declare
cursor cv4 is select nom_emp,service,nom_serv
cursor cv4 is select nom_emp,service,nom_serv
from emp,service
where service=num_serv;
from emp,service
where service=num_serv;
begin
begin
for ligne in cv4
for ligne in cv4
loop
loop
insert into liste
insert into liste
values(ligne.nom_emp,ligne.service,ligne.nom_serv);
values(ligne.nom_emp,ligne.service,ligne.nom_serv);
end loop;
end loop;
end;
end;

 les lments de la structure sont identifis par :


nom_structure.nom_colonne
 la structure est renseigne par le FETCH :
fetch nom_curseur INTO nom_structure;

PL/SQL (#1)

Jean-Luc GOERIG

Curseurs implicites (2)

 Curseur implicite = simplification dcriture 


 Dclaration implicite d'une structure dont les lments sont d'un type
identique aux colonnes ramenes par le curseur:

35/76

PL/SQL (#1)

Jean-Luc GOERIG

36/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseurs implicites (3)

Curseurs paramtrs(1)
 Curseurs paramtrs:
 Ils permettent de pouvoir rutiliser un mme curseur avec des
valeurs diffrentes dans un mme bloc PL/SQL.
 Les paramtres sont de type CHAR, NUMBER, DATE, BOOLEAN.
 Le passage des valeurs se fait l'ouverture du curseur.

 Dclaration du curseur directement dans une boucle FOR:


FOR nom_structure IN ( ordre select )
LOOP
traitement;
END LOOP;

Il n'y a plus de dclaration du curseur.


prompt curseur version2 implicite et boucle for
prompt curseur version2 implicite et boucle for
pause
pause
drop table liste;
drop table liste;
create table liste (col1 char(20),col2 char(20),col3 char(20));
create table liste (col1 char(20),col2 char(20),col3 char(20));
begin
begin
for cv5 in
for cv5 in
(select nom_emp,service,nom_serv
(select nom_emp,service,nom_serv
from emp,service where service=num_serv)
from emp,service where service=num_serv)
loop
loop
insert into liste
insert into liste
values(cv5.nom_emp,cv5.service,cv5.nom_serv);
values(cv5.nom_emp,cv5.service,cv5.nom_serv);
end loop;
end loop;
end;
end;

37/76

PL/SQL (#1)

DECLARE
DECLARE
CURSOR
CURSOR nom_curseur(param1
nom_curseur(param1 TYPE,
TYPE, param2
param2 TYPE,
TYPE, ...)
...)
IS
IS ordre
ordre select
select ....;
....;
--- utilisant
utilisant les
les paramtres
paramtres para1
para1 et
et para2
para2
BEGIN
BEGIN
OPEN
OPEN nom_curseur
nom_curseur (val1,
(val1, val2,
val2, ....);
....);
-ou
FOR
nom_structure
-- ou FOR nom_structure IN
IN nom_curseur
nom_curseur (val1,
(val1, val2,
val2, ...);
...);

Jean-Luc GOERIG

38/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseurs paramtrs(2)

Curseurs de mise jour(1)

 Exemple:

 Curseur avec la clause FOR UPDATE et CURENT OF:


 Ce type de curseur permet de verrouiller les lignes dune table
interroge par un curseur dans le but de mettre jour la table, sans
quun autre utilisateur ne la modifie en mme temps (accs
concurrents).
 Permet d'accder directement en modification (ordre UPDATE) ou
en suppression (ordre DELETE) la ligne que vient de ramener
l'ordre FETCH.
 Il faut au pralable rserver les lignes lors de la dclaration du
curseur par un verrou d'intention :

prompt curseur explicite paramtr


prompt curseur explicite paramtr
accept
accept numservice
numservice
declare
declare
cursor
cursor cv6
cv6 (param1
(param1 number)
number) is
is
select
select nom_emp,service,
nom_emp,service, nom_serv
nom_serv
from
emp,service
from emp,service where
where service=num_serv
service=num_serv
and
num_serv=param1;
and num_serv=param1;
vnom
emp.nom_emp%type;
vnom emp.nom_emp%type;
vnumserv
vnumserv emp.service%type;
emp.service%type;
vservice
vservice service.nom_serv%type;
service.nom_serv%type;
begin
begin
open
cv6(&numservice);
open cv6(&numservice);
fetch
fetch cv6
cv6 into
into vnom,
vnom, vnumserv,
vnumserv, vservice;
vservice;
while
while cv6%found
cv6%found
loop
loop
insert
insert into
into liste
liste values(vnom,vnumserv,vservice);
values(vnom,vnumserv,vservice);
fetch
fetch cv1
cv1 into
into vnom,
vnom, vnumserv,
vnumserv, vservice;
vservice;
end
loop;
end loop;
close
cv6;
close cv6;
End;
End;

39/76

PL/SQL (#1)

FOR UPDATE OF <nom_colonne>

 La modification ou la suppression utilisent la clause :


WHERE CURRENT OF nom_curseur

Jean-Luc GOERIG

40/76

PL/SQL (#1)

Jean-Luc GOERIG

Curseurs de mise jour(2)

Curseurs de mise jour (3)

 Exemple (dbut):

 Exemple (suite):

prompt
prompt curseur
curseur pour
pour mise
mise jour
jour
prompt
prompt changement
changement de
de service
service de
de tous
tous les
les employs
employs du
du bar
bar
insert
insert into
into service
service values
values (5,'fast-food');
(5,'fast-food');
select
select ** from
from emp,service
emp,service
where
where service=num_serv
service=num_serv and
and nom_serv
nom_serv like
like 'bar%';
'bar%';
declare
declare
vbar
vbar service.nom_serv%type
service.nom_serv%type :=
:= 'bar';
'bar';
vnom
vnom emp.nom_emp%type;
emp.nom_emp%type;
vnumserv
vnumserv emp.service%type;
emp.service%type;
vservice
vservice service.nom_serv%type;
service.nom_serv%type;
cursor
cursor cv6
cv6 is
is
select
select nom_emp,service,
nom_emp,service, nom_serv
nom_serv
from
from emp,service
emp,service
where
where service=num_serv
service=num_serv
and
and nom_serv
nom_serv like
like vbar
vbar
for
for update
update of
of service;
service;
begin
begin ...
...

41/76

PL/SQL (#1)

begin
begin
open
open cv1;
cv1;
fetch
fetch cv1
cv1 into
into vnom,
vnom, vnumserv,
vnumserv, vservice;
vservice;
while
while cv1%found
cv1%found
loop
loop
update
update emp
emp set
set service=5
service=5
where
where current
current of
of cv1;
cv1;
fetch
fetch cv1
cv1 into
into vnom,
vnom, vnumserv,
vnumserv, vservice;
vservice;
end
end loop;
loop;
close
close cv1;
cv1;
end;
end;
//
select
select ** from
from emp,service
emp,service
where
where service=num_serv
service=num_serv
and
and nom_serv
nom_serv like
like 'fast%';
'fast%';

Jean-Luc GOERIG

42/76

PL/SQL (#1)

Jean-Luc GOERIG

Traitement des erreurs (1)

Traitement des erreurs (2)

 La section EXCEPTION permet d'affecter un traitement appropri aux


erreurs survenues lors de l'excution d'un bloc PL/SQL.

 Le code PL/SQL qui traite lerreur est crit dans la section EXCEPTION
DECLARE
DECLARE
<nom_erreur>
<nom_erreur> EXCEPTION;
EXCEPTION;
BEGIN
BEGIN
IF
IF <condition_detection>
<condition_detection>
THEN
THEN RAISE
RAISE <nom_erreur>;
<nom_erreur>;
EXCEPTION
EXCEPTION
WHEN
WHEN <nom_erreur>
<nom_erreur> THEN
THEN
<traitement
<traitement erreur>;
erreur>;
[WHEN
[WHEN OTHERS
OTHERS THEN
THEN <traitements>;]
<traitements>;]
End;
End;

 Deux types d'erreurs sont possibles :


 erreurs spcifiques lapplication (user exception)
 erreurs internes ORACLE (SQLCODE !=0)

 Dclaration dune exception spcifique (user):


 Dclarer un nom pour chaque erreur dans section DECLARE
 Ecrire le traitement effectuer dans la partie EXCEPTION

 Sortie du bloc aprs un traitement exception :


 il faut dcouper le programme en sous bloc PL/SQL ou grer soit mme les
traitements d'erreurs en utilisant les attributs du curseur.
 Le WHEN OTHERS est toujours en dernier

 Les erreurs Oracle les plus courantes sont prdfinies


 Il y a sortie du bloc PL/SQL aprs traitement de lerreur
43/76

PL/SQL (#1)

Jean-Luc GOERIG

44/76

PL/SQL (#1)

Jean-Luc GOERIG

Traitement des erreurs (3)

Traitement des erreurs (4)

--- exemple
exemple exception
exception utilisateur
utilisateur
declare
declare
gros_salaire exception;
gros_salaire exception;
cursor
cursor cv1
cv1 is
is select
select nom_emp,
nom_emp, salaire,
salaire, nom_serv
nom_serv
from emp,service where service=num_serv;
from emp,service where service=num_serv;
vnom emp.nom_emp%type;
vnom emp.nom_emp%type;
vsalaire emp.salaire%type;
vsalaire emp.salaire%type;
vservice service.nom_serv%type;
vservice service.nom_serv%type;
begin
begin
dbms_output.enable;
dbms_output.enable;
open
open cv1;
cv1;
loop
loop
fetch
fetch cv1
cv1 into
into vnom,
vnom, vsalaire,
vsalaire, vservice;
vservice;
exit when cv1%notfound;
exit when cv1%notfound;
if vsalaire > 9999 then
raise gros_salaire;
if vsalaire > 9999 then
raise gros_salaire;
end if;
end if;
end loop;
end loop;
close cv1;
close cv1;
exception
exception
when gros_salaire then
when gros_salaire then
dbms_output.put_line('Exception gros_salaire! :'||vnom||' '||vsalaire);
dbms_output.put_line('Exception gros_salaire! :'||vnom||' '||vsalaire);
when others then null;
when others then null;
end;
end;

45/76

PL/SQL (#1)

Jean-Luc GOERIG

Traitement des erreurs (5)

PL/SQL (#1)

 Elles ne sont ni dclares, ni dtectes. Elles ont des noms pr-dfinis mais on peut
les changer. Elles sont associes un traitement dans la partie EXCEPTION
 Quelques erreurs courantes:

DUP_VAL_ON_INDEX
FETCH_OUT_OF
INVALID_CURSOR
INVALID_NUMBER
NO_DATA_FOUND
TOO_MANY_ROWS
VALUE_ERROR
ZERO_DIVIDE

-1
-1002
-1001
-1722
-1403
-1422
-6502
-1476

 SQLCODE renvoie le numro de l'erreur courante.


 SQLERRM [(code erreur)] renvoie le libell de l'erreur courante.

46/76

PL/SQL (#1)

Jean-Luc GOERIG

Exercice sur les curseurs

-- exemple exception too_many_rows


-- exemple exception too_many_rows
declare
declare
vnom emp.nom_emp%type;
vnom emp.nom_emp%type;
vnumserv emp.service%type;
vnumserv emp.service%type;
vservice service.nom_serv%type;
vservice service.nom_serv%type;
begin
begin
dbms_output.enable;
dbms_output.enable;
select nom_emp,service, nom_serv into vnom,vnumserv,vservice
select nom_emp,service, nom_serv into vnom,vnumserv,vservice
from emp,service
from emp,service
where service=num_serv;
where service=num_serv;
exception
exception
when TOO_MANY_ROWS then
when TOO_MANY_ROWS then
dbms_output.put('Exception TOO_MANY_ROWS: ');
dbms_output.put('Exception TOO_MANY_ROWS: ');
dbms_output.put_line('Il faut utiliser un curseur!');
dbms_output.put_line('Il faut utiliser un curseur!');
dbms_output.put_line('SQLCODE='||to_char(SQLCODE));
dbms_output.put_line('SQLCODE='||to_char(SQLCODE));
dbms_output.put_line('SQLERRM='||SQLERRM);
dbms_output.put_line('SQLERRM='||SQLERRM);
when others then
when others then
dbms_output.put_line('SQLCODE='||to_char(SQLCODE));
dbms_output.put_line('SQLCODE='||to_char(SQLCODE));
dbms_output.put_line('SQLERRM='||SQLERRM);
dbms_output.put_line('SQLERRM='||SQLERRM);
end;
end;
/
/

47/76

 Erreurs Oracle prdfinies:

La
Labase
basede
dedonnes
donnesde
delalasocit
socitVOYAGE-ECO
VOYAGE-ECOcomprend
comprend44tables
tables: :
CHAUFFEUR
nom) )
CHAUFFEUR (ncar,
(ncar,nom
VOYAGE
VOYAGE(ncar#,
(ncar#,datevoyage,
datevoyage,ville#
ville#) )
PRIME
(nom,
date
versement,
montant)
PRIME (nom, date versement, montant)
DESTINATION
seuil,base)
base)
DESTINATION(ville,
(ville,seuil,
Chaque
Chaquevoyage
voyageeffectu
effectudonne
donnelieu
lieul'insertion
l'insertiond'une
d'uneligne
lignedans
danslalatable
tableVOYAGE.
VOYAGE.
La
Laville
villereprsente
reprsentelaladestination
destinationdu
duvoyage.
voyage.
Un
Unchauffeur
chauffeurne
neconduit
conduitqu'un
qu'unseul
seulcar,
car,un
uncar
carn'est
n'estconduit
conduitque
quepar
parun
unseul
seulchauffeur.
chauffeur.
Les
Lesprimes
primessont
sontattribues
attribuesen
enfonction
fonctiondu
dunombre
nombrede
devoyages
voyageseffectus
effectuspar
pardestination,
destination,du
duseuil
seuiletet
de
delalabase.
base.
Ex
Ex: : La
Laligne
ligne(Bruxelles,
(Bruxelles,10,
10,120)
120)dans
danslalatable
tableDESTINATION
DESTINATIONsignifie
signifieque
que les
leschauffeurs
chauffeursayant
ayant
effectus
effectusplus
plusde
de10
10voyages
voyagesvers
versBruxelles
Bruxellesauront
aurontune
uneprime
primegale
gale120
120xx(nb
(nbde
devoyage
voyage- -10).
10).
Le
Lechauffeur
chauffeurayant
ayantralis
ralisleleplus
plusde
devoyage
voyagesur
surune
unedestination
destinationaura
auragalement
galementune
uneaugmentation
augmentation
de
de10%
10%de
delalaprime
primeacquise
acquisesur
surcette
cettedestination.
destination.
Le
Letraitement
traitementest
esteffectu
effectuchaque
chaquesemestre
semestreetetzro
zroou
ouune
uneligne
lignepar
parchauffeur
chauffeurest
estinsre
insredans
danslala
table
PRIME.
table PRIME.
Ensuite,
Ensuite,les
leslignes
lignesde
delalatable
tableVOYAGE
VOYAGEsont
sontsupprimes.
supprimes.
Ecrire
Ecrireleleprogramme
programmePL/SQL
PL/SQLqui
quiralise
raliseleletraitement
traitementsemestriel
semestrieldes
desprimes
primes

Jean-Luc GOERIG

48/76

PL/SQL (#1)

Jean-Luc GOERIG

Variables curseurs (REF CURSORS)

Variables curseurs (REF CURSORS)

 REF CURSOR:
 Une variable curseur est un curseur dynamique qui nest pas associ
une requte donne comme un curseur classique (statique).
 Une variable curseur permet au curseur dvoluer au cours du programme.
 Dclare en deux tapes:
 Dclaration du type
 Dclaration de la variable du type
DECLARE
DECLARE
TYPE
TYPE nomTypeCurseurDyn
nomTypeCurseurDyn IS
IS REF
REF CURSOR
CURSOR [[ RETURN
RETURN typeRetourSQL
typeRetourSQL ];
];
...
...

nom_du_curseur_dyn
nom_du_curseur_dyn

nomTypeCurseurDyn;
nomTypeCurseurDyn;

 le type du retour est en gnral la structure dun enregistrement dune table.


 Louverture du curseur est commande par linstruction OPEN <curseur>
FOR <requte SQL> crite dans la section BEGIN.
 La lecture du curseur sopre toujours avec linstruction FETCH

49/76

PL/SQL (#1)

Jean-Luc GOERIG

Variables curseurs (REF CURSORS)

DECLARE
DECLARE
TYPE
TYPE ref_pil
ref_pil IS
IS REF
REF CURSOR;
CURSOR;
cur_pil
cur_pil ref_pil;
ref_pil;
vnopil
vnopil transair.pilote.nopilote%TYPE;
transair.pilote.nopilote%TYPE;
vnom
vnom transair.pilote.nompil%TYPE;
transair.pilote.nompil%TYPE;
vadr
vadr transair.pilote.adresse%TYPE;
transair.pilote.adresse%TYPE;
vsal
vsal transair.pilote.salaire%TYPE;
transair.pilote.salaire%TYPE;
BEGIN
BEGIN
dbms_output.enable;
dbms_output.enable;
OPEN
OPEN cur_pil
cur_pil FOR
FOR SELECT
SELECT nopilote,nompil,adresse
nopilote,nompil,adresse
from
from transair.pilote
transair.pilote where
where comm
comm is
is not
not null;
null;
FETCH
FETCH cur_pil
cur_pil INTO
INTO vnopil,vnom,vadr;
vnopil,vnom,vadr;
WHILE
WHILE cur_pil%FOUND
cur_pil%FOUND LOOP
LOOP
dbms_output.put_line(vnopil||':'||vnom||':'||vadr);
dbms_output.put_line(vnopil||':'||vnom||':'||vadr);
FETCH
FETCH cur_pil
cur_pil INTO
INTO vnopil,vnom,vadr;
vnopil,vnom,vadr;
END
END LOOP;
LOOP;
CLOSE
CLOSE cur_pil;
cur_pil;
dbms_output.put_line('++++++++++++++++');
dbms_output.put_line('++++++++++++++++');
--- suite
suite sur
sur la
la diapo
diapo suivante
suivante

50/76

PL/SQL (#1)

Jean-Luc GOERIG

PL/SQL (#1)

Jean-Luc GOERIG

Notes

--- suite
suite du
du ref
ref cursor
cursor
dbms_output.put_line('++++++++++++++++');
dbms_output.put_line('++++++++++++++++');
OPEN
OPEN cur_pil
cur_pil FOR
FOR SELECT
SELECT nopilote,nompil,salaire
nopilote,nompil,salaire
from
from transair.pilote
transair.pilote where
where comm
comm is
is not
not null;
null;
FETCH
FETCH cur_pil
cur_pil INTO
INTO vnopil,vnom,vsal;
vnopil,vnom,vsal;
WHILE
WHILE cur_pil%FOUND
cur_pil%FOUND LOOP
LOOP
dbms_output.put_line(vnopil||':'||vnom||':'||vsal);
dbms_output.put_line(vnopil||':'||vnom||':'||vsal);
FETCH
FETCH cur_pil
cur_pil INTO
INTO vnopil,vnom,vsal;
vnopil,vnom,vsal;
END
END LOOP;
LOOP;
CLOSE
CLOSE cur_pil;
cur_pil;
END;
END;

 On observe dans ce programme que le mme curseur (cur_pil) sert pour


deux requtes SQL diffrentes.
 Ce type de curseur peut tre pass en paramtre dans une procdure
catalogue.

51/76

PL/SQL (#1)

Jean-Luc GOERIG

52/76

Procdures et Fonctions catalogues

Procdures (1)

 Une procdure est un sous-programme PL/SQL (ou Java) qui effectue


un traitement particulier.

 Une procdure est une unit de traitement qui peut contenir :


des commandes SQL de manipulation des donnes (LMD),
des instructions PL/SQL,
des variables, des constantes, des curseurs, un gestionnaire d'erreurs.

 Les procdures sont compiles et stockes dans la base de donnes,


comme tout autre objet (donne) manipul par le moteur du SGBD.
 Amlioration des performances: les procdures et fonctions nont plus
besoin d'tre analyses une seconde fois l'excution.

 La structure gnrale d'une procdure partir du bloc PL/SQL est la suivante :


PROCEDURE
PROCEDURE <nomprocedure>
<nomprocedure> [[ (parametres,...)]
(parametres,...)] {{ IS
IS || AS
AS }}
Dclaration
Dclaration des
des variables
variables locales;
locales;
BEGIN
BEGIN
Instructions
Instructions SQL
SQL et
et PL/SQL;
PL/SQL;
EXCEPTION
EXCEPTION
Traitement
Traitement des
des exceptions
exceptions (gestion
(gestion des
des erreurs);
erreurs);
END
END [nomprocedure];
[nomprocedure];

 Les procdures charges en mmoire pour excution seront partages


et rutilises par tous les objets qui la demandent (applications)
 Une fonction est un sous-programme qui renvoie une valeur.
 Les procdures et fonctions permettent dencapsuler les donnes
dune base.

 Le mot-cl Declare a t remplac par le mot-cl Procedure.

53/76

PL/SQL (#1)

Jean-Luc GOERIG

54/76

PL/SQL (#1)

Procdures (2)

Procdures (3)

 Cration d'une procdure stocke :

 Exemple: procdure AugmenterSalaire:

CREATE
CREATE [OR
[OR REPLACE]
REPLACE] PROCEDURE
PROCEDURE [schema].<nomprocedure>
[schema].<nomprocedure>
[[ (parametres,...)]
(parametres,...)]
{{ IS
|
AS
}
IS | AS }
Dclaration
Dclaration des
des variables
variables locales;
locales;
BEGIN
BEGIN
Instructions
SQL
et
PL/SQL;
Instructions SQL et PL/SQL;
EXCEPTION
EXCEPTION
des
exceptions;
des exceptions;
END;
END;
 Loption OR REPLACE permet de spcifier au systme le remplacement de la
procdure si elle existe dj dans la base de donnes.
 Les paramtres sont dfinis selon la syntaxe suivante :
nomparamtre [ IN | OUT | IN OUT ] type [ { := default } valeur]
IN : indique que la variable est passe en entre,
OUT : indique que la variable est renseigne par la procdure puis renvoye
l'appelant
IN OUT : passage par rfrence
Le type du paramtre ne doit pas contenir d'indication sur la longueur.

Jean-Luc GOERIG

CREATE
CREATE OR
OR REPLACE
REPLACE PROCEDURE
PROCEDURE AugmenterSalaire
AugmenterSalaire
(NumSal
(NumSal integer,
integer, Montant
Montant Real)
Real) IS
IS
SalaireActuel
SalaireActuel Real;
Real;
SalaireNull
SalaireNull Exception;
Exception;
BEGIN
BEGIN
Select
Select sal
sal into
into SalaireActuel
SalaireActuel From
From emp
emp
Where
Where empno
empno == NumSal
NumSal ;;
If
(SalaireActuel
is
NULL)
If (SalaireActuel is NULL)
then
then raise
raise SalaireNull
SalaireNull ;;
else
else Update
Update emp
emp set
set sal
sal == sal
sal ++ Montant
Montant
Where
empno
=
NumSal
;
Where empno = NumSal ;
End
End If;
If;
EXCEPTION
EXCEPTION
When
When no_data_found
no_data_found then
then
insert
insert into
into emp_audit
emp_audit values
values (NumSal,'Inconnu');
(NumSal,'Inconnu');
When
When SalaireNull
SalaireNull then
then
insert
insert into
into emp_audit
emp_audit values
values (NumSal,'Salaire
(NumSal,'Salaire Null');
Null');
END
END AugmenterSalaire;
AugmenterSalaire;

 La partie dclarative de la procdure constitue linterface


55/76

PL/SQL (#1)

Jean-Luc GOERIG

56/76

PL/SQL (#1)

Jean-Luc GOERIG

Procdures (4)

Procdures (5)

 Modification d'une procdure :

 Mise au point d'une procdure (dboguage) avec SQ*Plus:


La commande SHOW ERRORS permet de rcuprer les messages suivants :

 recompilation avec la commande:


ALTER PROCEDURE [schema].nomprocedure COMPILE ;

ERRORS FOR
LINE/COL
-----------3/24
5/0

 Suppression d'une procdure :


DROP PROCEDURE [schema].nomprocedure ;

 Excution : une procdure est appele comme une instruction PL/SQL


 Ex: appel pour augmenter le salaire d'un employ dans un autre sous-programme :
AugmenterSalaire(NumeroSalarie, Augmentation) ;

 Le dveloppeur peut interroger le dictionnaire de donnes pour obtenir des


informations sur les erreurs. Les vues du dictionnaire s'appellent :
USER_ERRORS
ALL_ERRORS
DBA_ERRORS
 Le texte source peut tre obtenu partir des vues suivantes :
USER_SOURCE
ALL_SOURCE
DBA_SOURCE
 Le dveloppeur peut galement utiliser le package public DBMS_OUTPUT pour
mettre au point ses procdures.

AugmenterSalaire(100, 1000);

 A partir d'un programme applicatif (programme hte)


EXEC SQL EXECUTE
BEGIN
AugmenterSalaire(100, 1000);
END;
END-EXEC ;

 SQL Developer possde un dbogueur intgr!

 A partir de Sql*Plus (EXECUTE):

 Le compte doit avoir le privilge systme DEBUG CONNECT SESSION

SQL> EXECUTE AugmenterSalaire(7788,1000) ;


SQL> EXECUTE AugmenterSalaire(8000,1000) ;

57/76

PL/SQL (#1)

PROCEDURE supprimer_emp ;
ERROR
------------------------------------------PL/SQL-00103 : Encountered the symbol "EMPNO" when ...
PL/SQL-00103 : Encountered the symbol "END" when ...

Jean-Luc GOERIG

58/76

PL/SQL (#1)

Fonctions (1)

Fonctions (2)

 Une fonction est un sous-programme qui renvoie une valeur.


 La structure d'une fonction est identique celle d'une procdure, mais les
fonctions possdent une clause RETURN.

 Exemple de fonction VerifierSalaire:

FUNCTION
FUNCTION nomfonction
nomfonction [[ (argument,...)]
(argument,...)]
RETURN
RETURN type
type {{ IS
IS || AS
AS }}
Dclarations
de
variables
Dclarations de variables locales;
locales;
BEGIN
BEGIN
Instructions
SQL
et
PL/SQL;
Instructions SQL et PL/SQL;
RETURN
RETURN (valeur);
(valeur);
EXCEPTION
EXCEPTION
Traitement
Traitement des
des exceptions;
exceptions;
END
END [nomfonction];
[nomfonction];

 Les arguments sont dfinis selon la syntaxe suivante :


(nomargument [IN] type [,nomargument [IN] type] ... )

 Le type de l'argument ne doit pas contenir d'indication sur la longueur.


 Le nom de la fonction est valoris par une valeur conforme au type par
l'instruction Return.
 Une fonction doit tre dclare avant d'tre utilise.
 Ne pas confondre les deux clauses RETURN: Return type et Return (valeur)
59/76

PL/SQL (#1)

Jean-Luc GOERIG

Jean-Luc GOERIG

CREATE
CREATE FUNCTION
FUNCTION VerifierSalaire
VerifierSalaire
(Numgrade
(Numgrade integer,
integer, Montant
Montant Real)
Real)
RETURN
RETURN boolean
boolean IS
IS
MinSalaire
MinSalaire Real;
Real;
MaxSalaire
MaxSalaire Real;
Real;
BEGIN
BEGIN
Select
Select losal,
losal, hisal
hisal into
into MinSalaire,
MinSalaire, MaxSalaire
MaxSalaire
From
salgrad
From salgrad
Where
Where grade
grade == Numgrade
Numgrade ;;
RETURN
(
(Montant
>=
RETURN ( (Montant >= MinSalaire)
MinSalaire) and
and (Montant
(Montant <=
<= MaxSalaire)
MaxSalaire) );
);
END
VerifierSalaire;
END VerifierSalaire;

60/76

PL/SQL (#1)

Jean-Luc GOERIG

Fonctions (3)

Fonctions (4)

 Cration dune fonction stocke:


CREATE
CREATE [OR
[OR REPLACE]
REPLACE] FUNCTION
FUNCTION nomfonction
nomfonction [[ (argument,.)]
(argument,.)]
RETURN
RETURN type
type {{ IS
IS || AS
AS }}
Dclarations
de
variables
Dclarations de variables locales;
locales;
BEGIN
BEGIN
Instructions
Instructions SQL
SQL et
et PL/Sql;
PL/Sql;
RETURN(Valeur);
RETURN(Valeur);
EXCEPTION
EXCEPTION
Traitement
Traitement des
des exceptions;
exceptions;
END
END ;;

 Retrouver la liste des sous-programmes crs dans la base:


Select owner, object_name, object_type, status
from dba_objects
where object_type in (PROCEDURE,FUNCTION,TRIGGER,PACKAGE)
and owner not in (SYS,SYSTEM)
order by owner, object_name;

 Retrouver le code dun sous-programme cr dans la base:


Select line, text from dba_source
where owner =ZORRO
and name = NOM_PROG
order by line;

 Recompilation dune fonction:


ALTER FUNCTION [schema].nomfonction COMPILE ;

 Suppression dune fonction:


DROP FUNCTION [schema].nomfonction ;

 Excution dune fonction dans un programme PL/SQL:


a:= VerifierSalaire(100, 1000)
EXEC SQL EXECUTE
BEGIN
a:=VerifierSalaire(100, 1000);
END;
END EXEC;
61/76

PL/SQL (#1)

Jean-Luc GOERIG

Procdures et fonctions avec Sql Developer

63/76

PL/SQL (#1)

62/76

PL/SQL (#1)

Jean-Luc GOERIG

Dboguer une procdure avec Sql Developer

Jean-Luc GOERIG

64/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

Tableaux, structures et collections en PL/SQL

 Il existe des types de donnes complexes utilises en PL/SQL:

 Typage et dclaration de variables simples:


Nom_var
Nom_var [constant]type[NOT
[constant]type[NOT NULL][:=
NULL][:= valeur
valeur || DEFAULT
DEFAULT expression];
expression];

 Rappel sur typage et dclaration de variable simples

 Exemples de dclaration:
XX NUMBER
NUMBER NOT
NOT NULL
NULL :=10.40;
:=10.40;
CC VARCHAR(100)
VARCHAR(100) :=
:= 'Coucou';
'Coucou';
NN CONSTANT
CONSTANT INTEGER
INTEGER DEFAULT
DEFAULT 100;
100;
VV BOOLEAN
BOOLEAN :=
:= TRUE;
TRUE;

 Les collections de type RECORD


 Les collections de type TABLE ou VARRAY

 Il existe plusieurs catgories de types de variables :

Simples (INTEGER, NUMBER, DATE, CHAR, BOOLEAN,


VARCHAR, ...) = scalaire
Type compos (RECORD, TABLE, VARRAY , NESTED TABLE)
Type rfrence (utilis en Objet-Relationnel)
Pointeur de LOB (CLOB, BLOB, BFILES, NCLOB )
Type 'dynamique' %TYPE qui dfinit une variable du type de la
colonne d'une table existante: nom emp.ename%TYPE

 Mthodes communes

65/76

PL/SQL (#1)

Jean-Luc GOERIG

66/76

PL/SQL (#1)

Tableaux, structures et collections en PL/SQL

Tableaux, structures et collections en PL/SQL

 Les collections (variables) de type RECORD:

 Les collections de type TABLE (variables tableaux):

TYPE
TYPE type_enr
type_enr IS
IS RECORD
RECORD
(( liste_de_types_avec_%TYPE_ou_non
liste_de_types_avec_%TYPE_ou_non || nom_table%ROWTYPE
nom_table%ROWTYPE );
);

 Elles permettent de dclarer une variable de type 'enregistrement' ou 'ligne


d'une table
 C'est donc un type structur dcomposable en colonnes lmentaires.
DECLARE
DECLARE
TYPE
TYPE t_rec_emp
t_rec_emp IS
IS RECORD
RECORD
(nom
(nom emp.ename%TYPE,
emp.ename%TYPE, salaire
salaire emp.sal%TYPE,
emp.sal%TYPE, comission
comission
emp.comm%TYPE);
emp.comm%TYPE);
rec_emp
rec_emp t_rec_emp;
t_rec_emp;

 Les RECORDS peuvent tre imbriqus et contenir d'autres RECORDS.


 Les RECORDS peuvent tre affects de manire lmentaire, champ par
champ, ou de manire globale grce un SELECT INTO :
rec_emp.salaire := 2400;
SELECT * INTO rec_emp FROM emp
WHERE empno = &no_saisi;
67/76

PL/SQL (#1)

Jean-Luc GOERIG

Une table PL/SQL:


 cest une collection ordonne dlment du mme type
 accessible uniquement en PL/SQL
 stocke en mmoire, elle peut grandir dynamiquement
 utilise des index non conscutif
 ils ont le mme format que des champs dune table
 on nutilise pas SQL pour sen servir
Dfinition :
TYPE
TYPE nom_tableau_pl
nom_tableau_pl IS
IS TABLE
TABLE OF
OF
<< type_scalaire
|
variable%TYPE
type_scalaire | variable%TYPE || table.colonne%TYPE
table.colonne%TYPE [NOT
[NOT
NULL]
NULL] || table%ROWTYPE
table%ROWTYPE || type_complexe
type_complexe >>
INDEX
INDEX BY
BY BINARY_INTEGER;
BINARY_INTEGER;

Declaration : mon_tableau nom_tableau_pl ;


Jean-Luc GOERIG

68/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

Tableaux, structures et collections en PL/SQL

 Exemple 1: tableau de 2 entiers

 Exemple 2: tableau de champs numriques

--- table
table de
de multiplication
multiplication par
par 88 et
et par
par 9...
9...
declare
declare
type
type tablemul
tablemul is
is record
record (( par8
par8 number,
number, par9
par9 number);
number);
type
type tabledentiers
tabledentiers is
is table
table of
of tablemul
tablemul
index
index by
by binary_integer;
binary_integer;
ti
ti tabledentiers;
tabledentiers;
ii number;
number;
begin
begin
for
for ii in
in 1..10
1..10 loop
loop
ti(i).par9
ti(i).par9 :=
:= i*9
i*9 ;;
ti(i).par8:=
ti(i).par8:= i*8;
i*8;
dbms_output.put_line
dbms_output.put_line (i||'*8='||ti(i).par8||'
(i||'*8='||ti(i).par8||'
'||i||'*9='||ti(i).par9
'||i||'*9='||ti(i).par9 );
);
end
end loop;
loop;
end;
end;

69/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

--- on
on va
va lire
lire les
les salaires
salaires de
de la
la table
table emp...
emp...
declare
declare
type
tsal
is
table
of
emp.sal%type
type tsal is table of emp.sal%type
index
index by
by binary_integer;
binary_integer;
tasal
tasal tsal;
tsal;
ii number;
number;
cursor
cursor cur
cur is
is select
select sal
sal from
from emp;
emp;
begin
begin
open
open cur;
cur;
ii :=1;
:=1;
loop
loop
exit
exit when
when cur%notfound;
cur%notfound;
fetch
fetch cur
cur into
into tasal(i)
tasal(i) ;;
dbms_output.put_line
dbms_output.put_line ('salaire
('salaire ...'||tasal(i));
...'||tasal(i));
ii :=
i
+
1;
:= i + 1;
end
end loop;
loop;
end;
end;
70/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

 Les collections VARRAY:

Exemple simple de varray:

TYPE
TYPE nom_type
nom_type IS
IS VARRAY
VARRAY (taille)
(taille) OF
OF
<< type_colonne
|
type_record
type_colonne | type_record >;
>;

 Un VARRAY stocke un ensemble ordonn d'lments.


 Chaque lment dispose d'un index qui lui est associe.
 Spcifier la taille maximale et le type des lments stocks dans le
VARRAY lors de la cration.
 Dans Oracle, les indices de tableau commencent partir du 1er, et non
de 0 (comme en C et Java).
 On utilise des VARRAY quand on connat lavance la taille de
lensemble de donnes et que cette taille est trs stable.
 Autre possibilit: on peut utiliser le DDL SQL CREATE TYPE.

DECLARE
DECLARE
TYPE
TYPE TYPE_TAB
TYPE_TAB IS
IS VARRAY
VARRAY (100)
(100) OF
OF VARCHAR2(1);
VARCHAR2(1);
TAB
TYPE_TAB
:=
TYPE_TAB(1,2,3,4);
TAB TYPE_TAB := TYPE_TAB(1,2,3,4);
BEGIN
BEGIN
TAB(1)
TAB(1) :=
:= 'T';
'T';
TAB(2)
TAB(2) :=
:= 'O';
'O';
TAB(3)
TAB(3) :=
:= 'T';
'T';
TAB(4)
TAB(4) :=
:= 'O';
'O';
FOR
LOOP
FOR II IN
IN 1..4
1..4
LOOP
DBMS_OUTPUT.PUT_LINE(TAB(I));
DBMS_OUTPUT.PUT_LINE(TAB(I));
END
END LOOP;
LOOP;
END;
END;

DECLARE
DECLARE
TYPE
TYPE t_tab_emp
t_tab_emp IS
IS VARRAY
VARRAY (1000)
(1000) OF
OF emp%ROWTYPE;
emp%ROWTYPE;
tab_emp
tab_emp t_tab_emp;
t_tab_emp; --- dclaration
dclaration de
de la
la variable
variable !!
71/76

PL/SQL (#1)

Jean-Luc GOERIG

72/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

Tableaux, structures et collections en PL/SQL

 Description des attributs / mthodes utilisables avec des TABLES


et VARRAY PL/SQL:

nom_table_sql.COUNT

retourne le nombre dlments de la table

nom_table_sql.DELETE

supprime toute la table

nom_table_sql.DELETE (n)

supprime llment n

73/76

ajoute un lment dans la table

PL/SQL (#1)

retourne le premier index du tableau

nom_table_sql.LAST

retourne la valeur du dernier index

nom_table_sql.TRIM

lment suivant

nom_table_sql.TRIM(n)

nom_table_sql.DELETE (n,m) supprime les lments de n m


nom_table_sql.EXTEND

nom_table_sql.FIRST

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

nom_table_sql.NEXT(n)

Retourne llment aprs ou avant le nime

nom_table_sql.PRIOR(n)

lment du tableau

74/76

PL/SQL (#1)

Jean-Luc GOERIG

Tableaux, structures et collections en PL/SQL

--- exemple
exemple dutilisation
dutilisation des
des attributs
attributs // mthodes
mthodes de
de TABLES
TABLES et
et VARRAY
VARRAY ::
declare
declare
type
type tsal
tsal is
is table
table of
of emp.sal%type
emp.sal%type index
index by
by binary_integer;
binary_integer;
tasal
tasal tsal;
tsal;
ii number;
number;
cursor
cursor cur
cur is
is select
select sal
sal from
from emp;
emp;
begin
begin
open
cur;
open cur;
ii :=1;
:=1;
loop
loop
exit
exit when
when cur%notfound;
cur%notfound;
fetch
fetch cur
cur into
into tasal(i)
tasal(i) ;;
ii :=
:= ii ++ 1;
1;
end
end loop;
loop;
close
close cur;
cur;
dbms_output.put_line('premier
dbms_output.put_line('premier lment:'||tasal(tasal.FIRST)
lment:'||tasal(tasal.FIRST) );
);
dbms_output.put_line('dernier
dbms_output.put_line('dernier lment:'||tasal(tasal.LAST)
lment:'||tasal(tasal.LAST) );
);
dbms_output.put_line('nombre
d
lment
:
'||tasal.COUNT);
dbms_output.put_line('nombre d lment : '||tasal.COUNT);
dbms_output.put_line('suppresion
dbms_output.put_line('suppresion des
des lments'||
lments'||
tasal.next(1)||'
tasal.next(1)||' '||tasal.prior(tasal.COUNT));
'||tasal.prior(tasal.COUNT));
tasal.delete(2,tasal.COUNT-1);
tasal.delete(2,tasal.COUNT-1);
dbms_output.put_line('nombre
dbms_output.put_line('nombre dd lment
lment :: '||tasal.COUNT);
'||tasal.COUNT);
end;
end;
75/76

PL/SQL (#1)

Jean-Luc GOERIG

Autre exemple de varray:


SQL> declare
2
type month_va is varray(13) of VARCHAR2(20);
3
v_month_va month_va;
4
v_count_nr number;
5 begin
6
v_month_va:=month_va('A','B','C','D','E','F','G');
7
DBMS_OUTPUT.put_line('Length:'||v_month_va.count);
8
9
v_month_va.extend;
10
v_month_va(v_month_va.last):='Null';
11
DBMS_OUTPUT.put_line('Length:'||v_month_va.count);
12
13
for i in v_month_va.first..v_month_va.last
14
loop
15
DBMS_OUTPUT.put_line('v_month_va(i): '||v_month_va(i));
16
end loop;
17 end;
18 /
Length:7
Length:8
v_month_va(i): A
v_month_va(i): B
v_month_va(i): C
v_month_va(i): D
v_month_va(i): E
v_month_va(i): F
v_month_va(i): G
v_month_va(i): Null
PL/SQL procedure successfully completed.

76/76

PL/SQL (#1)

Jean-Luc GOERIG

Vous aimerez peut-être aussi