Professional Documents
Culture Documents
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 3 / 63
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 4 / 63
1. Introduction AU PL/SQL
1.1.Introduction au PL/SQL
1.1.1. Les caractéristiques PL/SQL
- Procedural Language/SQL (PL/SQL) est une extension procédurale au SQL propre à Oracle. Le
PL/SQL possède les caractéristiques des langages de programmation procéduraux, tels que le C et
le FORTRAN, qui ne sont pas disponibles dans le SQL : l'encapsulation des données, le traitement
des exceptions, l'orientation objet…
- Le PL/SQL est un puissant langage de traitement des transactions.
- Le PL/SQL est un langage hybride : il utilise des ordres SQL pour accéder à la base de données et
des instructions PL/SQL pour contrôler les ordres SQL afin de traiter de façon explicite des
données.
- Le PL/SQL permet d'inclure la manipulation des données et les ordres SQL dans des blocs
structurés et dans des unités procédurales de code.
o Déclaration d’identifiants tels que des variables, des constantes, des curseurs, des exceptions
- Variables PL/SQL : déclaration de variables dont le type de données peut être simple ou
composé.
- Utilisation des identifiants dans les instructions SQL et dans les instructions procédurales.
- Attributs %TYPE et %ROWTYPE : déclaration dynamique de variables, en fonction de la
structure de données des colonnes d'une table et des tables de la base de données.
o Portabilité accrue :
- Déplacement de programme possible vers n’importe quel environnement prenant en charge
Oracle et PL/SQL (grâce aux fonctionnalités glisser-déplacer de Procédure Builder).
o Intégration :
- Réduction des problèmes d’intégration entre le serveur Oracle et les outils de développement.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 5 / 63
- Le PL/SQL est le langage commun au serveur Oracle (à travers les procédures stockées, les
triggers de base de données et les packages) et aux outils de développement d’Oracle (à
travers les triggers de Oracle Developer).
- Les bugs d’intégration sont également réduits, car les variables et types de données PL/SQL
et SQL sont compatibles. Ainsi, PL/SQL facilite l’accès pratique aux bases de données et
satisfait les besoins en terme de programmation procédurale.
Les blocs PL/SQL sont transmis de l'application au moteur PL/SQL du serveur Oracle. Ensuite, le
moteur PL/SQL fractionne les instructions SQL du bloc en instructions séparées, puis les envoie au
moteur SQL.
Si les blocs sont fractionnés en instructions SQL, un seul transfert est nécessaire entre l’application et
le serveur Oracle ce qui permet de réduire le trafic réseau et d’augmenter de façon significative les
performances, en particulier en architecture client/serveur.
Le moteur PL/SQL utilisé pour traiter le code dépend de l’emplacement du bloc de code PL/SQL. La
méthode de traitement du code sur le serveur Oracle est différente de celle utilisée dans les outils
Oracle. En effet, beaucoup d'outils Oracle possèdent leur propre moteur PL/SQL indépendant du
moteur PL/SQL présent sur le serveur Oracle.
Le moteur PL/SQL des outils Oracle filtre les instructions SQL du code de l’application et les envoie
individuellement vers le moteur SQL du serveur Oracle. Il exécute les instructions procédurales du
bloc PL/SQL avec le moteur procédural du moteur PL/SQL.
Le moteur procédural traite les données locales de l’application ce qui réduit le nombre de tâches
envoyées au serveur Oracle ainsi que le nombre de curseurs mémoire utilisés.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 6 / 63
Le serveur peut accueillir du code contenant un grand nombre d’instructions SQL afin de réduire le
nombre d’instructions SQL individuelles envoyées à travers le réseau.
Se mettent en minuscules :
- les identifiants et les paramètres, tels que v_sal, emp_cursor, g_sal, p_empno…
- les noms de tables et les noms de colonnes, tels que dept, emp, empno, ename…
Grâce à une convention de dénomination standard, le code est facile à lire et à mettre à jour.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 7 / 63
Section déclarative Elle contient toutes les déclarations des variables, constantes, curseurs et
exceptions définies par l’utilisateur et utilisées dans la section exécutable.
La section déclarative est facultative et doit commencer par le mot clé
DECLARE.
Section exécutable Elle contient des instructions SQL permettant de manipuler les données de
la base de données et des instructions PL/SQL permettant de manipuler les
données d’un bloc. La section exécutable est obligatoire et doit commencer
par le mot clé BEGIN.
Section de traitement Elle spécifie les actions à effectuer lorsque des erreurs ou des conditions
des exceptions anormales se produisent dans la section exécutable. La section de
traitement des exceptions est facultative et doit commencer par le mot clé
EXCEPTION.
Un bloc PL/SQL se termine par le mot-clé END suivi d’un point virgule.
Pour faciliter la lecture d’un bloc de code PL/SQL, chaque nouvelle instruction doit être sur une
nouvelle ligne et les différents niveaux des blocs doivent être mis en évidence par des retraits.
[DECLARE]
[<Section déclarative optionnelle>]
BEGIN
<Section exécutable obligatoire>
[EXCEPTION]
<Section de traitement des exceptions optionnelle>]
END;
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 8 / 63
DECLARE
v_ename VARCHAR2(5);
BEGIN
SELECT ename
INTO v_ename
FROM emp
WHERE empno = 1234;
EXCEPTION
WHEN NO_DATA_FOUND THEN
...
END;
Un bloc anonyme est un bloc PL/SQL non nommé, imbriqué dans une application ou créé de façon
interactive. Un bloc anonyme est déclaré dans une application à l’endroit de son exécution. Il est
ensuite passé au moteur PL/SQL pour être exécuté. Un bloc anonyme peut être imbriqué dans un
programme de pré-compilation et dans SQL*Plus (ou Server Manager). Les blocs anonymes sont
disponibles dans tous les environnements PL/SQL.
[DECLARE
<Déclarations>]
BEGIN
<Instructions>
[EXCEPTION
<Traitements des erreurs>]
END ;
Pour exécuter un bloc anonyme dans le buffer de SQL*Plus, il faut utiliser le caractère slash "/". Si le
bloc s'exécute avec succès, sans erreurs soulevées ni d'erreurs de compilation, le message suivant
s'affiche :
Il s’agit d’un bloc PL/SQL nommé et stocké sous forme d’objet de base de données dans le
dictionnaire de données du serveur Oracle. Il peut utiliser des paramètres d’entrée et de sortie, il peut
être invoqué de façon répétée et est disponible sur le serveur Oracle avec extension procédurale.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 9 / 63
Il s’agit d’une autre structure de programmation possédant les mêmes attributs (et même syntaxe)
qu’une procédure ou fonction stockée. Il s’agit d’un bloc PL/SQL nommé résidant dans une application
Oracle Developer ou dans une librairie partagée. Cette structure accepte les paramètres (entrée et
sortie), et peut être invoquée de façon répétée. Elle est disponible avec le serveur Oracle et les
composants de Oracle Developer.
Les packages
Il s’agit d’un bloc PL/SQL nommé regroupant des procédures, des fonctions et des identifiants
(curseurs, variables, constantes, exceptions, définition de collection) liés entre eux. Les packages sont
disponibles sur le serveur Oracle avec extension procédurale.
PACKAGE nom IS
PROCEDURE nom (arguments) ;
…
END ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 10 / 63
Il s’agit d’un bloc PL/SQL associé à une table de la base de données. Il est exécuté automatiquement
lors de la manipulation du contenu de la table à laquelle il est attaché. Le trigger de base de données
est disponible sur le serveur Oracle.
- Un identifiant peut comporter un maximum de 30 caractères et doit commencer par une lettre.
- Le nom d’un identifiant doit être différent des noms des colonnes des tables (au quel cas le
moteur interprète l’identifiant comme une référence à la colonne).
- Les chaînes de caractères et les dates figurant dans les instructions PL/SQL doivent être
inclues entre simples quotes.
- Les expressions numériques sont représentées soit par une valeur simple, soit par une
notation scientifique.
- Les commentaires sur plusieurs lignes doivent être inclus entre les caractères " /* " et " */ "
(Ces symboles sont à éviter après le mot clé SELECT car ils sont utilisés dans ce cas comme
indicateur pour l’optimisateur). Les caractères "- -" sont utilisés pour mettre une seule ligne en
commentaire.
- Les unités lexicales doivent être séparées à l’aide d’un ou plusieurs espaces ou délimiteurs.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 11 / 63
2. VARIABLES ET TYPES DE
DONNEES
2.1.Les types de données PL/SQL
2.1.1. Utilisation et traitement des variables
Une variable est un espace de stockage temporaire de données.
Une fois déclarées, les variables peuvent être utilisées de façon répétée dans une application
simplement en les référençant dans d'autres ordres même déclaratifs.
Les valeurs stockées par la variable peuvent être manipulées.
PL/SQL prend en charge quatre types de données qui peuvent être utilisés pour la déclaration de
variables, de constantes, de pointeurs ou de localisateurs :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 12 / 63
INTEGER Entier.
POSITIVE Entier positif
Entiers entre -2 147 483 647 et
BINARY_INTEGER
NUMBER 2 147 483 947.
NUMBER [(précision,
Nombre flottant
degré)]
Entiers signés entre -2 147 483 647 et
PLS_INTEGER
2 147 483 947.
Chaîne de caractères variables (jusqu’à 32 760
LONG
octets).
Chaîne de caractères variables (jusqu’à 32 767
VARCHAR2
CHAR octets, pas de valeur par défaut)
Chaîne de caractère fixe (jusqu’à 32767 octets, si
CHAR [(maximum_length)]. maximum_length n'est pas spécifié, alors sa taille est
1).
Date et heure. La tranche des dates est de 4712 B.C.
DATE
à 9999 A.D.
Type de données pouvant stocker trois valeurs
BOOLEAN possibles utilisées pour les calculs logiques : TRUE,
FALSE ou NULL.
Type de données stockant des données binaires. Sa
RAW (maximum_size) taille maximale est de 2 000 octets. Ce type n'est pas
interprété par le PL/SQL.
RAW
Type de données stockant des données binaires. Sa
LONG RAW
taille maximale est de 32 760 octets. Ce type n'est
(maximum_size)
pas interprété par le PL/SQL.
Les valeurs PLS_INTEGER requiert moins d'espace de stockage et sont plus rapide que les valeurs
NUMBER et BINARY_INTEGER.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 13 / 63
Exemple :
DECLARE
v_location VARCHAR(13) := 'Atlanta' ;
v_deptno NUMBER(2) NOT NULL := 10 ;
c_comm CONSTANT NUMBER DEFAULT 100 ;
v_hiredate DATE := SYSDATE + 7 ;
v_valid BOOLEAN NOT NULL := TRUE ;
v_count BINARY_INTEGER := 0 ;
v_location est une variable déclarée qui stocke la location d'un département.
v_deptno est une variable déclarée qui stocke le numéro d'un département, qui ne
peut pas contenir une valeur nulle et dont la valeur par défaut est 10.
c_comm est une constante déclarée correspondant à une commission et dont la
valeur par défaut est 100.
v_hiredate est une variable déclarée correspondant à une date d'embauche et dont
la valeur par défaut est la date du jour additionnée de 7 jours.
v_valid est un indicateur déclaré précisant la validité ou non des données et initialisé
à TRUE.
v_count est une variable déclarée qui compte le nombre d'itérations dans une boucle
et dont la valeur par défaut est 0.
Les chaînes de caractères littérales doivent être placées entre simple quotes, par exemple : 'Hello,
World'. Si la chaîne contient une apostrophe, il faut doubler l'apostrophe. Par exemple, pour insérer la
valeur Luke, I'm your father, la chaîne doit être écrit ainsi 'Luke, I''m your father'.
Deux objets (dont les variables) peuvent avoir le même nom à condition qu'ils soient définis dans des
blocs différents.
Les identifiants ont une longueur maximale de 30 caractères. Le premier caractère doit être une lettre,
les caractères suivants peuvent être des lettres, des nombres ou des caractères spéciaux.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 14 / 63
Identifiant := expr ;
Exemples :
v_hiredate := '31-DEC-98';
Æ Cet assignement n'est possible que dans la version 8i d'Oracle. Les versions
antérieures requièrent la fonction TO_DATE.
v_ename := 'Maduro';
Il existe une autre façon d'assigner une valeur à une variable : de sélectionner (SELECT) ou de
ramener (FETCH) des valeurs dans la base de données.
Exemple :
Plutôt que d’écrire explicitement le type de données et la précision, une variable peut être déclarée en
fonction d’une colonne de base de données grâce à l’attribut %TYPE.
%TYPE est très utile dans la mesure où la déclaration de la variable ne nécessite pas de connaître le
type exacte des données de la colonne de la base de données dont elle va accueillir les valeurs.
PL/SQL détermine le type de données et la précision de la variable de la variable lors de la
compilation du bloc.
De plus, si le type de données de la colonne change dans la base de données, le type de données de
la variable déclarée à l’aide du type %TYPE sera modifié par un recompilation automatique.
Exemple :
v_ename emp.ename%TYPE ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 15 / 63
Si une variable est déclarée avec %TYPE et référence une colonne définie comme NOT NULL, la
valeur de cette variable peut être quand même être NULL. En effet, la contrainte NOT NULL sur la
colonne ne s'applique pas automatiquement sur la variable. La contrainte NOT NULL doit être
appliquée à la variable pour interdire les valeurs nulles.
Exemple :
v_ename emp.ename%TYPE ;
Æ La contrainte NOT NULL est appliquée à la variable, donc elle ne peut pas
contenir une valeur nulle.
L’attribut %TYPE peut aussi être utilisé pour déclarer une variable présentant le même type de
données qu’une autre variable déclarée précédemment.
Exemple :
v_balance NUMBER(7,2) ;
v_min_balance v_balance%TYPE := 10 ;
Une table PL/SQL est un tableau à une dimension (une seule colonne utilisable) dynamique,
inconsistant constitué d'éléments homogènes (données du même type) et indexé par des nombres
entiers.
Elle est donc composée de deux colonnes :
- La première colonne est la clé primaire qui sert à indexer la table PL/SQL. Le type de données
de cette colonne est BINARY_INTEGER. ( de -2 147 483 647 à 2 147 483 647). L'index n'est
pas obligé de commencer à 1 et peut être négatif.
- La seconde colonne est du type de données scalaire ou RECORD, elle stocke les éléments de
la table PL/SQL.
Attention, une table PL/SQL est différente d’une table de base de données. Il ne faut pas confondre la
clé primaire d'une table de base de données avec la clé primaire d'une table PL/SQL. Elles n'ont pas le
même rôle.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 16 / 63
Exemple :
PRMARY
COLUMN
KEY
… …
1 Jones
2 Smith
3 Maduro
… …
Avant d'utiliser une table PL/SQL, il faut d'abord déclarer un type de données TABLE car il n'existe
pas de types de données TABLE prédéfinies, et ensuite déclarer une variable PL/SQL de ce type.
Exemples :
La collection VARRAY permet d'associer un identifiant unique à une collection entière (un tableau).
Cette association permet de manipuler la collection dans son ensemble et de référencer facilement
chaque élément.
Une collection VARRAY possède une taille maximale qui doit être spécifiée dans sa définition. Son
index à une limite inférieure fixée à 1 et une limite supérieure fixée lors de la déclaration du type.
Syntaxe :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 17 / 63
type_name est un type spécifique utilise plus tard pour déclarer une variable
VARRAY.
size_limit est un entier positif littéral déterminant le nombre de poste dans la
collection (VARRAY).
element_type correspond au type de données PL/SQL des éléments de la collection.
Si le type de données est du type RECORD, tous les champs du RECORD doivent
être du type scalaire ou objet.
Le type des éléments peut être également défini avec %ROWTYPE ou %TYPE.
Exemples :
Après avoir créer le type de la collection, il faut déclarer une variable de ce type :
Identifiant type_name ;
Tan qu'elle n'est pas initialisée, une collection est NULL (ce ne sont pas ses éléments qui sont NULL
mais la collection elle-même). Pour initialiser une collection, il faut utiliser un constructeur. Un
constructeur est une fonction définie par le système ayant le même nom que le type de la collection.
Cette fonction "construit" la collection en lui passant des valeurs.
Exemple :
DECLARE
TYPE CourseList IS VARRAY(20) OF VARCHAR2(10);
my_courses CourseList;
my_courses2 CourseList := CourseList('Prog','Engl','Hist');
my_courses3 CourseList := CourseList();
BEGIN
my_courses := CourseList('Math','Eco',NULL,'Management');
IF my_courses3 IS NOT NULL THEN
...
END IF;
END;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 18 / 63
que my_courses3 est initialisé comme une collection vide (attention elle n'est pas
nulle, mais vide, donc la condition de la boucle IF retournera TRUE).
Note : Cette méthode d'initialisation à l'aide d'un constructeur est applicable aux tables PL/SQL
indexée.
Le moteur PL/SQL n'appelle jamais implicitement un constructeur, il doit donc être appelé
explicitement.
Exemple :
BEGIN
INSERT INTO Student
VALUES (5035, 'Mickey Mouse','122 Disney St',
CourseList('Eco','Geo','Hist','Eng','Math',...));
...
Les méthodes d'interrogation des collections TABLE et VARRAY ont des procédures ou des
fonctions qui opèrent sur des tables et qui permettent d'obtenir diverses informations sur des tables.
collection_name.method_name [ (parameters) ]
Méthode Description
EXISTS(n) Retourne TRUE si le n-ième élément existe dans une table PL/SQL.
COUNT Retourne le nombre d'éléments que contient une table PL/SQL.
FIRST Retourne le premier et le dernier (le plus petit et le plus grand) numéro d'index dans
LAST une table PL/SQL. Retourne NULL si la table PL/SQL est vide.
PRIOR(n) Retourne le numéro d'index qui précède le numéro d'index n dans une table PL/SQL.
NEXT(n) Retourne le numéro d'index qui suit le numéro d'index n dans une table PL/SQL.
Augmente la taille d'une table PL/SQL.
EXTEND EXTEND ajoute un élément null à une table PL/SQL.
* EXTEND(n) ajoute n éléments null à une table PL/SQL.
EXTEND(n, i) ajoute n copies de l'élément i existant dans une table PL/SQL.
TRIM supprime le dernier élément d'une table PL/SQL.
TRIM *
TRIM(n) supprime les n dernier éléments d'une table PL/SQL.
DELETE supprime tous les éléments d'une table PL/SQL.
DELETE DELETE(n) supprime le n-ième élément d'une table PL/SQL.
DELETE(m,n) supprime tous les éléments dans la tranche m à n d'une table PL/SQL.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 19 / 63
Pour référencer un élément d'une table PL/SQL, il faut utiliser la syntaxe suivante :
collection_name(index)
index doit être est un entier (qui peut être issue d'une expression). Cet entier doit
être compris entre -2**31 et 2**31 en ce qui concerne les tables PL/SQL, et entre 1
et la limite supérieur définie dans le type en ce qui concerne les tableaux.
Exemple :
ename_collection(3)
Exemple :
DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
TYPE hiredate_table_type IS TABLE OF DATE
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
hiredate_table hiredate_table_type;
BEGIN
ename_table(1) := 'CAMERON';
hiredate_table(8) := SYSDATE + 7;
IF ename_table.EXISTS(1) THEN
INSERT INTO ...
...
END;
Pour pouvoir être affectée le contenu d'une collection à une autre, les deux collections doivent être du
même type.
Deux collections ne peuvent pas être comparées dans une égalité oud ans une inégalité.
Des collections ne peuvent pas apparaître dans une liste DISTINCT, GROUP BY ou ORDER BY.
Exemple :
DECLARE
TYPE Admin IS VARRAY(60) OF Person;
TYPE Student IS VARRAY(600) OF Person;
Prepa1 Student := Student(...);
Prepa2 Student := Student(...);
Prof Admin := Prof(...);
BEGIN
Prepa2 := Prepa1;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 20 / 63
Le type PL/SQL RECORD permet de déclarer un enregistrement PL/SQL pouvant stocker une ligne
constituée de colonnes possédant chacune son propre nom et son propre type de données. Ces
colonnes sont appelées des champs. Ces champs sont créés lors de la déclaration de l’enregistrement
PL/SQL.
Avant d'utiliser un enregistrement PL/SQL, il faut d'abord déclarer un type de données RECORD car
il n'existe pas de types de données RECORD prédéfinis pour les enregistrements PL/SQL, et ensuite
déclarer une variable PL/SQL de ce type.
L’attribut %TYPE peut être utilisé pour définir le type de données des champs.
%TYPE peut référencer le type de données d'une variable précédemment déclarée
ou le type de données d'une colonne d'une table de base de données.
field_type est un type de données PL/SQL (sauf le type REF CURSOR).
Un enregistrement peut posséder autant de champs (field_name) que nécessaire.
Identifiant type_record_name ;
Les types RECORD et les enregistrements peuvent être définis et déclarés dans la section déclarative
d'un bloc, d'un sous-programme ou d'un package.
Par exemple :
Une table stocke des données sur les employés, telles que le numéro d'identification
(empno), le nom (ename) et la fonction (job) d’un employé. Ces colonnes ne sont pas
semblables, mais elles sont logiquement liées. Un enregistrement PL/SQL permet de
traiter cet ensemble de champs comme une seule unité logique.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 21 / 63
Exemple :
DECLARE
TYPE emp_record_type IS RECORD
( empno emp.empno%TYPE NOT NULL :=100,
ename emp.ename%TYPE,
job emp.job%TYPE ) ;
emp_record1 emp_record_type ;
emp_record2 emp_record_type ;
BEGIN
...
END ;
Un type RECORD peut être le composant d’un autre type RECORD, c’est à dire être imbriqué dans un
autre type RECORD.
Exemple :
La structure d’un enregistrement PL/SQL est semblable à celle d’un enregistrement défini dans un
langage de troisième génération (L3G). Par contre, sa structure est différente de celle d’une ligne
d’une table de base de données.
Un type RECORD peut contenir un ou plusieurs champs de type RECORD. Les types RECORD
peuvent donc être imbriqués.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 22 / 63
%ROWTYPE est un attribut utilisé pour déclarer un enregistrement PL/SQL pouvant stocker une
ligne entière de données sélectionnée dans une table ou une vue.
identifiant table_name%ROWTYPE ;
Cet attribut est utile lors de l’extraction d’une ou plusieurs lignes à l’aide de l’instruction SELECT ou
à l’aide d’un curseur explicite.
Exemple :
emp_record emp%ROWTYPE;
Exemple :
DECLARE
emp_rec emp%ROWTYPE;
BEGIN
SELECT * INTO emp_rec
FROM emp
WHERE empno = &employee_number;
INSERT INTO retired_emps(empno, ename, job, mgr, hiredate,
leavedate, sal, comm, deptno)
VALUES ( emp_rec.empno, emp_rec.ename, emp_rec.job,
emp_rec.mgr, emp_rec.hiredate, SYSDATE, emp_rec.sal,
emp_rec.comm, emp_rec.deptno);
COMMIT;
END;
ÆCe bloc recherche dans la table EMP l'employé dont le numéro a été saisi par
l'utilisateur (&employee_number). Les renseignements relatifs à cet employé sont
stockés dans un enregistrement PL/SQL emp_rec. Cet enregistrement va servir à
insérer l'employé concerné dans la table RETIRED_EMPS.
Pour référencer et/ou initialiser un champ dans un enregistrement, il faut utiliser la syntaxe suivante :
record_name.field_name
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 23 / 63
Exemple :
emp_record.job
emp_record.job := 'CLERK' ;
Exemple :
Colonne de la table
Clé primaire Champ1 de Champ2 de Champ3 de
de la table l'enregistrement l'enregistrement l'enregistrement
empno number(4) ename varchar2(10) job varchar2(9)
1 7566 JONES MANAGER
2 7369 SMITH SALESMAN
… … … …
table(index).field
Exemple :
DECLARE
TYPE dept_table_type IS TABLE OF dept%ROWTYPE
INDEX BY BINARY_INEGER;
dept_table dept_table_type;
-- each element of dept_table is a record
BEGIN
dept_table(2).job := 'CLERK';
...
END;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 24 / 63
De la même façon, une collection RECORD peut être imbriquée dans une collection VARRAY (cf
Exemple § 2.3.1.3 Définir une collection VARRAY).
Une variable hôte est une variable déclarée dans l'environnement hôte utilisée pour passer des valeurs,
en entrée ou en sortie d'un ou plusieurs programmes PL/SQL. Des ordres PL/SQL peuvent référencer
des variables déclarées dans l'environnement hôte sauf si ces ordres se trouvent dans une procédure,
une fonction ou un package.
La longueur de la variable devra être précisé pour les types de chaîne de caractères.
Exemple :
Pour afficher, sous SQL*Plus, toutes les variables hôtes définies et leurs types de données ou le type
de données d'une variable hôte donnée:
VAR[IABLE] {variable_name}
Pour afficher, sous SQL*Plus, la valeur courante de toutes les variables hôtes ou d'une variable hôte
donnée :
PRI[NT] {variable_name}
Pour faire référence à des variables hôtes ou des variables de substitution, vous devez faire précéder
les variables hôtes de deux points (:) et les variables de substitution d'un ampersand afin de les
distinguer des variables PL/SQL déclarées.
:host_variable := expression
&substitution_variable := expression
'&substitution_variable' := expression
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 25 / 63
Opérateurs Opérations
** NOT Exponentiation, négation logique
+ - Identité, négation
* / Multiplication, division
+ - || Addition, soustraction, concaténation
=, !=, <, >, <=, >=, IS NULL, LIKE, BETWEEN,
Comparaison
IN
AND Conjonction
OR Inclusion
Exemple :
DECLARE
v_n1 NUMBER := 500;
v_n2 NUMBER := 1003;
v_value BOOLEAN;
v_valid BOOLEAN;
BEGIN
v_value := (v_n1 = v_n2);
v_valid := (v_value IS NOT NULL);
END;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 26 / 63
Comme dans SQL, l'ordre dans lequel les opérations sont effectuées peut être contrôlé à l'aide de
parenthèses.
- GREATEST(), LEAST()
Les fonctions non disponibles dans les instructions procédurales sont les fonctions de groupe suivantes
: AVG(), MIN(), MAX(), COUNT(), SUM(), STDDEV(), VARIANCE(), et la fonction DECODE.
conversion_function(value,format)
Exemple :
v_comment := USER||':'||TO_CHAR(SYSDATE);
Æ USER est une fonction SQL qui retourne une valeur de type CHAR contenant le
nom de l'utilisateur courant. Cette valeur est concaténée à la chaîne ' ; '. La fonction
SYSDATE retourne une valeur de type DATE. Cette valeur est convertie par la
fonction TO_CHAR en une valeur de type CHAR. Ainsi, la valeur retournée par la
fonction TO_CHAR peut être concaténée au reste de la chaîne. Le résultat de la
concaténation est stocké dans la variable v_comment.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 27 / 63
La portée d’un objet est la partie d’un programme pouvant faire référence à un objet. La portée
s’applique à tous les objets déclarés, à savoir les variables, les curseurs, les exceptions définis par
l’utilisateur et les constantes. Lorsqu’une variable est déclarée dans un bloc, elle est visible dans le
bloc et ses sous blocs imbriqués.
Cette règle s'applique à tous les objets : les variables, les curseurs, les exceptions définies par
l'utilisateur et les constantes.
Exemple :
...
x BINARY_INTEGER ;
BEGIN Portée de x
...
DECLARE
Y NUMBER ;
BEGIN Portée de y
...
END ;
...
END ;
Une variable est également visible pour tous les blocs de la procédure ou de la fonction dans laquelle
elle est déclarée.
Si un bloc ne trouve pas la variable déclarée localement, il recherche en amont dans la section
déclarative des blocs qui l'imbriquent (appelés blocs parents). Le bloc ne recherche jamais en aval
dans les blocs imbriqués (appelés blocs enfants).
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 28 / 63
SELECT select_list
INTO { variable_name [variable_name,...] | record_name }
FROM table_list
[WHERE condition] ;
La requête ne doit retourner qu'une seule ligne. Si elle ne retourne aucune ligne ou plus d'une ligne,
alors une erreur est générée.
En PL/SQL, la clause INTO est obligatoire dans l’instruction SELECT. La clause INTO est requise
pour le stockage des valeurs extraites dans des variables scalaires (variable_name) ou dans un
enregistrement PL/SQL (record_name).
En plus de son usage habituel, la clause WHERE peut être aussi utilisée pour spécifier des variables
d’entrée, des constantes, des valeurs littérales ou des expressions PL/SQL.
Afin d’éviter des erreurs de syntaxe et les ambiguïtés, certaines règles doivent être respectées lors de
l’utilisation de l'ordre SELECT..INTO :
- Les colonnes de la base de données et les identifiants, tels que les variables, doivent avoir des
noms différents.
- Le nombre de variable dans la clause INTO doit être identique au nombre de colonnes
sélectionnées dans la clause SELECT. Leurs positions doivent correspondre.
- Le type de données des identifiants doit correspondre à celui des colonnes. Dans ce cas, l'attribut
%TYPE peut être utile pour assurer la compatibilité des types de données.
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 29 / 63
DECLARE
v_orderdate ord.orderdate%TYPE;
v_shipdate ord.shipdate%TYPE;
v_id ord.id%TYPE := 100;
BEGIN
SELECT orderdate, shipdate
INTO v_orderdate, v_shipdate
FROM ord
WHERE id = v_id ;
END ;
Pour extraire toutes les colonnes d’une ligne appartenant à une table, il faut utilisé un enregistrement
PL/SQL dans la clause INTO.
Exemple :
DECLARE
v_id dept.id%TYPE := 1;
dept_record dept%ROWTYPE;
BEGIN
SELECT *
INTO dept_record
FROM dept
WHERE id = v_id ;
END ;
Les exceptions produites peuvent être traitées à l’aide de routines de traitements d’exceptions.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 30 / 63
Lors de l’insertion de données dans toutes les colonnes de la ligne, il n’est pas nécessaire de préciser le
nom des colonnes.
L'instruction INSERT peut utiliser des fonctions SQL, peut générer des valeurs de clé primaire en
utilisant des séquences dans la base de données, utiliser des variables définies dans le bloc PL/SQL,
ajouter des valeurs de colonne par défaut
Exemple :
DECLARE
v_ename emp.ename%TYPE := 'LILI' ;
v_job emp.job%TYPE := 'TEACHER' ;
v_deptno emp.deptno%TYPE := 10 ;
BEGIN
INSERT INTO emp (empno, ename, job, deptno)
VALUES (empno_sequence.NEXTVAL, v_ename, v_job, v_deptno);
END ;
UPDATE table_name
SET colonne = variable [, colonne2 = variable2…]
[WHERE condition] ;
Exemple :
DECLARE
v_sal_increase emp.sal%TYPE := 20;
BEGIN
UPDATE emp
SET sal = sal + v_sal_increase
WHERE job = 'ANALYST' ;
END ;
Æ Tous les employés de la table EMP dont la fonction est ANALYST voient leur
salaire s'augmenter de $20.
Si la clause WHERE est omise, toutes les lignes de la table sont supprimées.
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 31 / 63
DECLARE
v_deptno emp.deptno%TYPE := 1234;
BEGIN
DELETE FROM emp
WHERE deptno = v_deptno ;
END ;
3.3.Curseurs SQL
3.3.1. Les caractéristiques des curseurs SQL
Lorsqu’une commande SQL est exécuté, le serveur Oracle réserve une zone de la mémoire pour
l ‘analyse et l’exécution de cette commande. Cette zone est appelé curseur SQL ou curseur implicite.
Un curseur SQL ne peut pas être ouvert ou fermé par un programme.
PL/SQL traite implicitement le curseur et le ferme, mais ne gère pas l’ouverture du curseur.
Les attributs des curseurs SQL ne peuvent pas être utilisés dans des ordres SQL; mais ils peuvent être
utilisés dans la section de traitement des exceptions d'un bloc PL/SQL.
Exemple :
Æ Tous les enregistrements de la table item dont le numéro de ordid vaut 605 sont
effacés de la table. SQL%ROWCOUNT affecte le nombre d'enregistrements effacés
à la "bind" variable rows_deleted. Ensuite la valeur de cette variable est affichée
avec la commande PRINT.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 32 / 63
COMMIT [WORK] ;
Exemple :
DECLARE
v_deptno emp.deptno%TYPE := 50 ;
BEGIN
DELETE FROM emp
WHERE deptno = v_deptno ;
COMMIT ;
END ;
Des commandes explicites de verrouillage, telles LOCK TABLE et SELECT..FOR UPDATE (cf…),
peuvent être utilisées dans un bloc. Dans ce cas, le verrouillage prend effet jusqu'à la fin de la
transaction. (Attention, un bloc PL/SQL n'implique pas nécessairement une transaction)
ROLLBACK [WORK] ;
Exemple :
DECLARE
v_deptno emp.deptno%TYPE := 50 ;
BEGIN
DELETE FROM emp
WHERE deptno = v_deptno ;
ROLLBACK ;
END ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 33 / 63
SAVEPOINT marqueur ;
Exemple :
BEGIN
INSERT INTO temp (num_col1, num_col2, char_col)
VALUES (1, 1, ‘ROW 1’);
SAVEPOINT a;
SAVEPOINT b;
SAVEPOIINT c;
ROLLBACK TO SAVEPOINT b;
END ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 34 / 63
Des instructions peuvent être exécutées de façon sélective en fonction d’une condition, à l’aide de
l’instruction IF.
IF condition THEN
statements ;
[ELSIF condition THEN
statements ; ]
[ELSE
statements ; ]
END IF ;
La boucle IF-THEN-END IF
IF-THEN-END IF est l'ordre IF simple qui permet d'effectuer des actions sous certaines conditions.
Si la condition booléenne est vraie, la séquence d'ordres associée est exécutée. Si la condition
booléenne est fausse ou nulle, la séquence d'ordre associée n'est pas exécutée.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 35 / 63
Exemple :
...
IF v_ename = 'MILLER' THEN
v_job := 'SALESMAN' ;
v_deptno := 30 ;
v_new_comm := sal * 0.20 ;
END IF ;
...
IF condition1 THEN
IF condition2 THEN
IF condition3 THEN
...
END IF;
...
END IF;
...
END IF;
La boucle IF-THEN-ELSE-END IF
Cette boucle possède une clause ELSE qui permet d'exécuter une séquence d'ordres spécifique si la
condition de la boucle est fausse ou nulle.
IFcondition THEN
statements1 ;
ELSE
Statements2 ;
END IF ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 36 / 63
Si la condition booléenne est vraie, la séquence d'ordres associée au IF est exécutée. Si la condition
booléenne est fausse ou nulle, la séquence d'ordre associée à la clause ELSE est exécutée.
Exemple :
...
IF v_ename = 'KING' THEN
v_job := 'MANAGER';
ELSE
v_job := 'CLERK';
END IF;
...
Tout comme les ordres associés à la clause IF, les ordres associés à la clause ELSE peuvent contenir
des ordres IF imbriqués. Par exemple :
IFcondition1 THEN
...
IF condition2 THEN ...
END IF;
...
ELSE
...
IF condition2 THEN
...
ELSE
...
END IF;
...
END IF ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 37 / 63
La boucle IF-THEN-ELSIF-END IF
Cette boucle possède une clause ELSIF qui est utilisée pour faciliter l'écriture, en effet une clause
ELSIF et équivalente à un ordre IF imbriquée.
IF condition1 THEN
statements1 ;
ELSIF condition2 THEN
statements2 ;
ELSE
Statements4 ;
END IF ;
Est equivalent à :
IF condition1 THEN
statements1 ;
ELSE
IF condition2 THEN
statements3 ;
ELSE
statements4 ;
END IF;
END IF ;
Une instruction IF peut contenir plusieurs clauses ELSIF mais qu'une seule clause ELSE.
Exemple :
...
IF v_deptno = 10 THEN v_comm := 5000 ;
ELSIF v_deptno = 20 THEN v_comm := 7500 ;
ELSIF v_deptno = 30 THEN v_comm := 3000;
ELSE v_comm := 2000 ;
END IF;
...
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 38 / 63
Exemple :
v_sal = (v_comm * 4)
Une condition booléenne complexe est la combinaison de plusieurs conditions simples avec des
opérateurs logiques tels que AND, OR et NOT.
Exemple :
v_result := (NOT v_tag1) L’opérateur NOT opère sur une condition unique
NOT
TRUE FALSE
FALSE TRUE
NULL NOT NULL
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 39 / 63
LOOP
statement1 ;
statement2 ;
…
statementN ;
END LOOP ;
A chaque fois que le flux de l’exécution rencontre l’instruction END LOOP, le contrôle est renvoyé à
la première instruction de la boucle. Sous cette forme, la boucle élémentaire est infinie.
L’instruction EXIT permet de sortir de la boucle. L'instruction EXIT peut être utilisée en tant
qu’action dans une instruction IF, ou comme instruction autonome dans la boucle.
LOOP LOOP
statement1 ; statement1 ;
statement2 ; statement2 ;
… …
statementN ; statementN ;
Dans le cas où l'instruction EXIT est utilisée comme une instruction autonome, la condition de la
clause WHEN doit être une variable booléenne ou une expression retournant une valeur booléenne.
Une boucle LOOP peut contenir plusieurs conditions de sortie.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 40 / 63
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 41 / 63
Exemple :
DECLARE
v_ordid item.ordid%TYPE := 601 ;
v_counter NUMBER(2) := 1 ;
BEGIN
LOOP
INSERT INTO item (ordid, itemid)
VALUES (v_ordid, v_counter);
V_counter := v_counter + 1 ;
EXIT WHEN v_counter > 10 ;
END LOOP;
END;
Æ Ce bloc permet d'insérer les dix lignes dans la table ITEM dont les identifiant des
lignes insérées vont de 1 à 10 et dont le numéro d'ordre est de 601 pour chaque
ligne insérée.
Le compteur (index) est déclaré, initialisé et incrémenté (ou décrémenté) implicitement. Lorsque le
contrôle entre dans la boucle, les limites inférieures (lower_limit) et supérieure (lower_limit) sont
utilisées pour déterminer le nombre d’exécutions de la boucle.
Si la valeur de la limite supérieure est inférieure à la valeur de la limite inférieure, la boucle ne
s’exécute pas.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 42 / 63
Exemple :
DECLARE
v_ordid item.ordid%TYPE := 601;
BEGIN
FOR i IN 1..10
LOOP
INSERT INTO item(ordid,itemid)
VALUES(v_ordid,i);
END LOOP ;
END ;
Æ Ce bloc insère dans la table ITEM dix nouvelles lignes dont l'identifiant correspond
à l'index de la boucle i, et dont le numéro d'ordre est 601.
WHILE condition
LOOP
statement1 ;
statement2 ;
…
statementN ;
END LOOP ;
La condition de la boucle WHILE peut être altérée par les instructions de la boucle.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 43 / 63
Exemple :
La fin d’une boucle imbriquée ne provoque pas l’arrêt de la boucle externe, sauf si une exception est
levée. Les étiquettes permettent de sortir d’une boucle externe en fonction de la valeur d’une boucle
interne.
Une étiquette est un identifiant déclaré qui désigne de façon facultative une instruction ou un bloc vers
lequel le contrôle doit être transféré.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 44 / 63
<<outer>>
LOOP
…
LOOP
…
EXIT outer WHEN …
END LOOP ;
…
END LOOP outer ;
L'instruction EXIT provoque la sortie de la boucle outer, donc des deux boucles à la
fois.
La précision d'un label dans la clause END LOOP est facultative et est utilisée pour clarifier le code.
Exemple :
...
BEGIN
<<outer_loop>>
LOOP
v_counter := v_counter + 1 ;
EXIT WHEN v_counter > 10 ;
<<inner_loop>>
LOOP
...
EXIT outer_loop WHEN total_done = 'YES';
-- leave both loops
EXIT WHEN inner_done = 'YES';
-- leave inner loop only
...
END LOOP inner_loop;
...
END LOOP outer_loop;
END;
Æ Ce bloc possède deux boucles. La boucle externe est identifiée par le label
outer_loop, la boucle interne est identifiée par le label inner_loop. La boucle interne
est imbriquée dans la boucle externe. Les noms des labels sont inclus dans l'ordre
END LOOP pour des raisons de clarté.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 45 / 63
Les curseurs implicites et explicites réalisent la même fonction, à savoir la fourniture d’espace
mémoire pour le traitement des lignes. La différence entre eux réside dans la façon dont ils sont
déclarés :
- Un curseur implicite est automatiquement (implicitement) déclaré par PL/SQL lors de l'exécution
d'instructions PL/SQL et DML (telles que INSERT, UPDATE et DELETE).
- Un curseur explicite est déclaré et nommé par le programmeur. Les curseurs explicites sont
manipulés grâce à des instructions spécifiques dans la section exécutable d'un bloc.
L’avantage de la création d’un curseur explicite est de pouvoir l’utiliser pour traiter plusieurs
ensembles de résultats de lignes. Le traitement dans un curseur explicite se fait ligne par ligne au-delà
de la première ligne renvoyée par la requête.
L'instruction SELECT..INTO ne doit retourner qu'une seule ligne. Un curseur explicite permet de
gérer des requêtes retournant plusieurs lignes et de traiter chaque ligne individuellement.
Les lignes renvoyées par une requête sont appelées ensemble actif. PL/SQL définit automatiquement
la taille du curseur en fonction de la taille de l’ensemble actif.
Un curseur explicite possède un pointeur inhérent qui enregistre la ligne courante (actuellement en
cours de traitement) de l’ensemble actif.
- Déclaration du curseur :
Un curseur explicite est déclaré en le nommant et en définissant la structure de la requête dont
il stockera le résultat.
- Ouverture du curseur :
L’instruction OPEN est utilisée pour ouvrir un curseur explicite. L’instruction exécute la
requête et identifie l’ensemble actif (résultat de la requête).
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 46 / 63
Elle charge la ligne actuelle du curseur dans les variables. Pour accéder à une ligne à la fois,
l’extraction doit être effectuée à l'intérieure d'une boucle.
- Fermeture du curseur :
L’instruction CLOSE permet de fermer un curseur explicite. L’instruction CLOSE libère
l’ensemble actif du curseur.
CURSOR cursor_name IS
Select_statement ;
Exemple :
DECLARE
CURSOR emp_cursor IS
SELECT empno, sal * 10
FROM emp;
CURSOR dept_cursor IS
SELECT *
FROM dept
WHERE deptno = 10 ;
BEGIN
...
END ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 47 / 63
OPEN cursor_name ;
L’instruction OPEN :
- alloue de façon dynamique de la mémoire pour une zone de contexte destinée à contenir les
informations de traitement.
- parse la requête associée au curseur.
- "binds" les variables en entrée.
- identifie l'ensemble actif.
- positionne le pointeur juste avant la première ligne du curseur.
Si le curseur est déclaré avec la clause FOR UPDATE, l'ordre OPEN verrouille les lignes retournées
par la requête.
La clause INTO contient les noms des variables ou le nom d'un enregistrement
PL/SQL dans lequel les données de l'ensemble actif seront stockées pour permettre
le traitement.
L’instruction FETCH :
- avance le pointeur à la prochaine ligne de l'ensemble actif.
- lit les données de la ligne courante de l'ensemble actif.
- extrait les valeurs de la ligne actuelle et les places dans les variables de la clause INTO.
Le nombre de variables à déclarer dépend du nombre de champs retournés par l'ordre FETCH. La
clause INTO de l’instruction FETCH autant de variables qu'il y a de colonnes dans la clause SELECT
de la requête associée au curseur.
Pour chaque valeur de colonne retournée par la requête associée au curseur, il doit y avoir une variable
qui lui correspond dans la clause INTO. Les types de données des variables doivent être compatibles
aux types de données des colonnes qui leur correspondent.
Le pointeur du curseur avance jusqu’à la ligne suivante à chaque exécution de la commande FETCH.
Exemple :
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp;
BEGIN
OPEN emp_cursor;
FOR i IN 1..10
LOOP
FETCH emp_cursor INTO v_empno, v_ename;
...
END LOOP;
...
END ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 48 / 63
Si une instruction FECTH ne retourne aucune valeur, aucune erreur n'est retournée. C'est pourquoi le
statut du curseur doit être contrôlé à l'aide d'attributs (paragraphe 5.3 Les attributs des curseurs
explicites).
CLOSE cursor_name ;
L'instruction CLOSE :
- désactive le curseur (l'ensemble actif devient indéfini).
- libère des ressources pouvant être utilisées pour l’extraction d’autres tâches.
Bien qu’il soit possible de terminer le bloc PL/SQL sans fermer le curseur, il est préférable de le
fermer explicitement.
De plus, le nombre de curseurs ouverts pour chaque utilisateur est limité par le paramètre de base de
données OPEN_CURSORS qui vaut, par défaut, 50.
L’accès aux données n’est plus possible après la fermeture d’un curseur.
Si une tentative d’accès aux données à partir d’un curseur fermé est effectuée, une exception
INVALID_CURSOR est levée.
Exemple :
...
BEGIN
OPEN emp_cursor;
FOR i IN 1..10
LOOP
FETCH emp_cursor INTO v_empno, v_ename;
...
END LOOP;
CLOSE emp_cursor;
END ;
Æ Le curseur emp_cursor est ouvert. Les dix premières lignes de l'ensemble actif de
emp_cursor sont traitées une par une. emp_cursor est fermé lorsque son traitement
est terminé (en dehors de la boucle).
cursor_name%ISOPEN
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 49 / 63
NOT cursor_name%ISOPEN
Exemple :
BEGIN
...
IF NOT emp_cursor%ISOPEN THEN
OPEN emp_cursor ;
END IF ;
LOOP
FETCH emp_cursor ...
END LOOP;
CLOSE item_cursor ;
...
END ;
cursor_name%FOUND
Exemple :
…
BEGIN
OPEN emp_cursor ;
FETCH emp_cursor INTO v_empno, v_ename ;
WHILE emp_cursor%FOUND
LOOP
INSERT INTO emp2 VALUES (v_empno, v_ename) ;
FETCH emp_cursor INTO v_empno, v_ename ;
END LOOP ;
END ;
Æ Ce bloc insère les valeurs du curseur dans la table EMP2 tant que le pointeur du
curseur n'est pas arrivé à la fin de l'ensemble actif.
Le contrôle de l’état d’un curseur à l’aide de l’attribut %FOUND permet d'assurer que le curseur
contient toujours des données à traiter.
cursor_name%NOTFOUND
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 50 / 63
…
BEGIN
OPEN emp_cursor ;
LOOP
FETCH emp_cursor INTO v_empno, v_ename;
EXIT WHEN emp_cursor%NOTFOUND OR
emp_cursor%NOTFOUNT IS NULL;
END LOOP ;
END ;
cursor_name%ROWCOUNT
Exemple :
…
BEGIN
OPEN emp_cursor ;
LOOP
FETCH emp_cursor INTO v_empno, v_ename ;
EXIT WHEN emp_cursor%ROWCOUNT > 5 ;
END LOOP ;
END ;
FORrecord_name IN cursor_name
LOOP
statements ;
END LOOP ;
Une boucle de curseur FOR sélectionne une plage de lignes d’une table de base de données, puis
extrait chaque ligne de cette plage. Cette procédure est différente de la boucle FOR classique (appelée
boucle FOR numérique), dans laquelle une plage de valeurs numériques est spécifiée, puis chaque
valeur de cette plage est traitée.
Les paramètres d’un curseur peuvent être spécifiés entre parenthèses après le nom du curseur dans
l’instruction FOR.
La boucle de curseur FOR ne doit pas être utilisée lorsque les opérations sont traitées manuellement.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 51 / 63
Exemple :
SET SERVEROUTPUT ON
DECLARE
CURSOR emp_cursor IS
SELECT ename, deptno
FROM emp ;
BEGIN
FOR emp_record IN emp_cursor
-- implicit open and implicit fetch
LOOP
IF emp_record.deptno = 30 THEN
DBMS_OUTPUT.PUT_LINE ('Employee '||
emp_record.ename || ' works in the Sales Dept.');
-- display
END IF;
END LOOP ; -- implicit close cursor
END ;
Æ La boucle FOR extrait une par une les lignes de l'ensemble actif de emp_cursor.
Chaque ligne est stockée dans l'enregistrement emp_record, implicitement déclaré.
Si la valeur du champ deptno de emp_record vaut 30, alors s'affiche à l'écran
"Employee [emp_record.ename] works in the Sales Dept." où emp_record.ename est
le nom de l'employé stocké dans l'enregistrement.
FORrecord_name IN (select_statement)
LOOP
statements ;
END LOOP ;
Exemple :
BEGIN
FOR emp_record IN (SELECT ename, deptno
FROM emp)
LOOP
IF emp_record.deptno = 30 THEN
...
END IF;
END LOOP;
END;
Le curseur auquel WHERE CURRENT OF fait référence doit exister, sinon une erreur sera générée.
Lors de l’utilisation de la clause WHERE CURRENT OF dans un ordre SQL, il est nécessaire
d’utiliser la clause FOR UPDATE dans la requête du curseur. La clause FOR UPDATE verrouille
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 52 / 63
toutes les lignes identifiées par la requête du curseur. Le verrouillage de la ligne permet de garantir
qu’elle ne sera pas traitée par d’autres utilisateurs lors de sa mise à jour ou de sa suppression.
CURSOR cursor_name IS
SELECT select_list
FROM table_list
[WHERE condition]
FOR UPDATE [OF column_reference] [NOWAIT] ;
Dans le cas d'une grosse mise à jour sur une grosse table, tous les enregistrements peuvent être
verrouillés avec l'ordre LOCK TABLE. Si l'ordre LOCK TABLE est utilisé, la clause WHERE
CURRENT OF ne peut pas être utilisée. Il faut utiliser la clause traditionnelle WHERE column =
identifier.
Exemple :
PROCEDURE ma_procedure IS
CURSOR emp_cursor IS
SELECT id, salary, start_date
FROM s_emp
WHERE dept_id = 41
FOR UPDATE OF salary ;
BEGIN
FOR emp_record IN emp_cursor LOOP
UPDATE s_emp
SET salary = salary * 2 ;
WHERE CURRENT OF emp_cursor;
END LOOP ;
COMMIT ;
END ;
Le nom du paramètre doit être suivi d’un type de données scalaire. La taille des données des
paramètres ne doit pas être spécifiée. Les valeurs des paramètres sont transmises au curseur lors de son
ouverture. Ces valeurs sont utilisées dans la requête du curseur lors de son exécution.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 53 / 63
Exemple :
DECLARE
CURSOR emp_cursor ( p_job emp.job%TYPE,
p_deptno emp.deptno%TYPE) IS
SELECT ename, empno, hiredate
FROM emp
WHERE deptno= p_deptno
AND job = p_job ;
BEGIN
OPEN emp_cursor('ANALYST',20);
...
END ;
Exemple :
DECLARE
CURSOR my_cursor IS
SELECT t1.deptno, t1.dname, t2.STAFF
FROM dept t1, ( SELECT deptno, COUNT(*) STAFF
FROM emp
GROUP BY deptno) t2
WHERE t1.deptno = t2.deptno
END t2.STAFF >= 5 ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 54 / 63
Si une exception est levée dans la section exécutable d'un bloc, l'exécution du bloc rejoint ("branches")
le traitement correspondant à l'exception dans la section de gestion des exceptions du bloc. Si le
moteur PL/SQL traite avec succès l'exception, alors l'exception n'est pas propagée au bloc "père" ni à
l'environnement. Dans ce cas, le bloc PL/SQL se termine alors avec succès.
Si une exception est levée dans la section exécutable d'un bloc et qu'il n'existe pas de traitement pour
cette exception. Le bloc PL/SQL se termine avec une erreur d'exécution ("failure") et l'exception est
propagée dans l'environnement.
Les erreurs du serveur Oracle prédéfinies correspondent approximativement aux 20 erreurs qui
apparaissent le plus souvent dans un bloc PL/SQL. Elles ne sont pas déclarées et sont levées
automatiquement par le serveur Oracle.
Les erreurs du serveur Oracle non prédéfinies correspondent à toutes les autres erreurs standard qui
peuvent apparaître dans un bloc PL/SQL. Elles sont déclarées dans la section déclarative et sont
automatiquement levées par le serveur Oracle.
Les erreurs définies par l'utilisateur correspondent à des conditions que le développeur a jugé
anormales. Elles sont déclarées dans la section déclarative et sont levées explicitement par le
développeur dans la section exécutive.
Note : Des applications avec des clients PL/SQL, tel que Oracle Developer Forms, possèdent leurs
propres exceptions.
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 55 / 63
Syntaxe :
EXCEPTION
WHEN exception1 [OR exception2...] THEN
statement1;
statement2;
...
[WHEN exception3 [OR exception4...] THEN
statement1;
statement2;
...]
[WHEN OTHERS THEN
statement1;
statement2;
...]
Exemple :
BEGIN
EXCEPTION
WHEN NO_DATA_FOUND THEN
statement1;
statement2;
WHEN TOO_MANY_ROWS THEN
statement1;
WHEN OTHERS THEN
statement1;
statement2;
statement3;
END;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 56 / 63
Numéro de
l'erreur du
Nom de l'exception Description
serveur
Oracle
ACCESS_INTO_NULL ORA-06530 Des valeurs ont essayé d'être assignées à des
attributs d'un objet non initialisé
COLLECTION_IS_NULL ORA-06531 Des méthodes autres que EXISTS ont essayé
d'être appliquées à un tableau ou une table
imbriquée.
CURSOR_ALREADY_OPEN ORA-06511 Un curseur a essayé d'être ouvert.
DUP_VAL_ON_INDEX ORA-00001 Une valeur existante a essayé d'être insérée.
INVALID_CURSOR ORA-01001 L'opération sur un curseur illégale s'est produite.
INVALID_NUMBER ORA-01722 La conversion de chaînes de caractères en nombre
a échoué.
LOGIN_DENIED ORA-01017 La connexion à Oracle a été réalisé avec un nom
d'utilisateur invalide ou un mot de passe.
NO_DATA_FOUND ORA-01403 Un ordre SELECT ne retourne aucune donnée.
NOT_LOGGED_ON ORA-01012 Un programme PL/SQL interroge une base de
données sans être connecté à Oracle.
PROGRAM_ERROR ORA-06501 Le moteur PL/SQL a un problème interne.
ROWTYPE_MISMATCH ORA-06504 La variable d'un curseur hôte et la variable d'un
curseur invoquées dans un assignement ont des
types de données retournés invalides.
STORAGE_ERROR ORA-06500 Il n'y a pas assez de mémoire pour le moteur
PL/SQL ou la mémoire est corrompu.
SUBSCRIPT_BEYOND_COUNT ORA-06533 L'élément d'une table imbriquée ou d'un tableau a
été référencé en utilisant un numéro d'index plus
grand que le nombre d'éléments contenu dans la
collection.
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 L'élément d'une table imbriquée ou d'un tableau a
été référencé en utilisant un numéro d'index qui
est en dehors des limites légales (-1 par exemple).
TIMEOUT_ON_RESSOURCE ORA-00051 "Time-out occured while Oracle is waiting for a
ressource"
TOO_MANY_ROWS ORA-01422 Un ordre SELECT retourne plus d'une ligne.
VALUE_ERROR ORA-06502 Une erreur arithmétique, de conversion, de
troncation ou de contrainte de taille est apparu.
ZERO_DEVIDE ORA-01476 Une division par zéro a été tenté.
exception EXCEPTION;
2. Associer le nom de l'exception à un numéro d'erreur Oracle à l'aide du pragma (appelé aussi
pseudo-instruction) EXCEPTION_INIT dans la section déclarative. Ce pragma permet de
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 57 / 63
référencer n'importe quelle exception interne par un nom et d'y rattacher un traitement spécifique
dans la section de gestion des exceptions.
Syntaxe :
Un pragma est une directive de compilateur, un pragma peut être vu comme une remarque entre
parenthèses faite au compilateur. Un pragma est traité au moment de la compilation et non de
l'exécution.
Le pragma EXCEPTION_INIT peut être déclaré dans la section déclarative d'un bloc PL/SQL ou
dans un package.
La déclaration du pragma doit apparaître quelque part après la déclaration de l'exception dans la
même section déclarative.
Section de gestion
Section déclarative des exceptions
Exemple :
DECLARE
e_emps_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT (e_emps_remaining, -2292);
v_deptno dept.deptno%TYPE := &p_deptno;
BEGIN
DELETE FROM dept
WHERE deptno = v_deptno;
COMMIT;
EXCEPTION
WHEN e_emps_remaining THEN
DBMS_OUTPUT.PUT_LINE('Cannot remove department ' ||
TO_CHAR(v_deptno) || ', Employees
exist.');
END;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 58 / 63
Ce bloc PL/SQL gère le cas où un département ne peut pas être supprimé car il
reste des employés dans ce département. Un message explicatif s'affiche alors à
l'utilisateur.
Exemple :
DECLARE
v_error_code NUMBER;
v_error_message VARCHAR2(255);
BEGIN
...
EXCEPTION
...
WHEN OTHERS THEN
ROLLBACK;
v_error_code:=SQLCODE;
v_error_message:=SQLERRM;
INSERT INTO errors
VALUES(v_error_code, v_error_message);
END;
exception EXCEPTION;
RAISE exception;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 59 / 63
Syntaxe :
Exemple :
DECLARE
E_invalid_product EXCEPTION;
BEGIN
UPDATE product
SET describ = '&product_description'
WHERE prodid = &product_number;
IF SQL%NOTFOUND THEN
RAISE e_invalid_product;
END IF;
COMMIT;
EXCEPTION
WHEN e_invalid_product THEN
DBMS_OUTPUT.PUT_LINE('Invalid product number.');
END;
Syntaxe :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 60 / 63
...
BEGIN
...
DELETE FROM emp
WHERE mgr = v_mgr;
...
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20201, 'This is not a valid
manager');
END;
Exemple :
...
BEGIN
...
DELETE FROM emp
WHERE mgr = v_mgr;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20201, 'This is not a valid
Manager');
END IF;
...
Dans les deux exemples, l'erreur -20201 est une exception définie par le
développeur, ce n'est pas une erreur standard du serveur Oracle. Le développeur a
défini son exception par un numéro d'erreur qui n'existe pas parmi les standards du
serveur Oracle et par un message.
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 61 / 63
Dans cet exemple, il s'agit de la création d'un bloc PL/SQL nommé, soit une
procédure appelée raise_salary. Cette procédure récupère le salaire d'un employé
dont le numéro est passé en paramètre. Si le salaire de l'employé est nul, alors la
procédure RAISE_APPLICATION_ERROR est appelée. Sinon la procédure met à
jour le salaire de l'employé dans la base en lui ajoutant une augmentation passée en
paramètre.
Ce bloc ci-dessous est placé dans le code d'une application, par exemple du code
Pro*C. Ce bloc déclare une exception et lui associe un numéro d'erreur. Ce numéro
d'erreur correspond à une exception définie par l'utilisateur : -20101. Ce bloc appelle
la procédure, déclarée ci avant, raise_salary. Si la procédure lève l'exception -20101,
ce sera le bloc PL/SQL inclus dans le code Pro*C qui la traitera et non la procédure
elle-même. L'application peut ainsi récupérer directement l'erreur et le message qui
lui est associé.
Exemple :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 62 / 63
BEGIN
BEGIN
IF x = 1 THEN
RAISE A;
ELSIF x = 2 THEN
RAISE B;
ELSE
RAISE C;
END IF
...
EXCEPTION L'exception A est traitée
WHEN A THEN localement, puis l'exécution
...
END;
reprend dans le bloc "père"
EXCEPTION
WHEN B THEN
...
END;
Quand une exception se propage dans un bloc "père", les actions exécutables restantes dans le sous-
bloc sont contournées.
Exemple 2 :
BEGIN
BEGIN
IF x = 1 THEN
RAISE A;
ELSIF x = 2 THEN
RAISE B;
ELSE
RAISE C;
END IF
...
EXCEPTION
WHEN A THEN L'exception B se propage
... dans le premier bloc "père"
END;
avec une routine appropriée.
EXCEPTION
WHEN B THEN
...
END;
L'exception B est traitée,
puis le contrôle passe dans
l'environnement hôte.
Exemple 3 :
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs
Notions de base du PL/SQL 63 / 63
BEGIN
BEGIN
IF x = 1 THEN
RAISE A;
ELSIF x = 2 THEN
RAISE B;
ELSE
RAISE C;
END IF
...
EXCEPTION
WHEN A THEN
...
END;
L'exception B n'a pas de routine dans
EXCEPTION le sous-bloc ni dans le bloc "père",
WHEN B THEN donc une exception non traitée est
...
END; retournée à l'environnement hôte.
Un des avantages de la propagation est que des ordres qui requièrent leurs propres traitements
d'exceptions peuvent être inclus dans des sous blocs en laissant les traitements d'exception plus
généraux dans les blocs "pères".
Une exception déclarée dans un bloc est considérée comme local pour ce bloc et global pour tous les
sous blocs.
Une exception ne peut pas être déclarée deux fois dans un même bloc, mais elle peut être déclarée
deux fois dans deux blocs différents. C'est l'exception locale qui prévaut sur l'exception globale. Pour
référencer l'exception globale, il faut utiliser des blocs labellisés :
block_label.exception ;
http://www.labo-oracle.com
Ce document est la propriété de Supinfo et est soumis aux règles de droits d’auteurs