Vous êtes sur la page 1sur 63

Module n°4

NOTIONS DE BASE DU PL/SQL


1Z0-001

Auteur : Aurélie Vuaroqueaux


Version 1.3 – 7 août 2003
Nombre de pages : 63

Ecole Supérieure d’Informatique de Paris


23. rue Château Landon 75010 – PARIS
www.supinfo.com
Notions de base du PL/SQL 2 / 63

Table des matières


1. INTRODUCTION AU PL/SQL ....................................................................................................................... 4
1.1. INTRODUCTION AU PL/SQL .......................................................................................................................... 4
1.1.1. Les caractéristiques PL/SQL................................................................................................................. 4
1.1.2. Les avantages du PL/SQL ..................................................................................................................... 4
1.1.3. Les fonctionnalités du moteur PL/SQL ................................................................................................. 5
1.2. CONVENTIONS DE PROGRAMMATION PL/SQL .............................................................................................. 6
1.2.1. La convention du code .......................................................................................................................... 6
1.2.2. La convention de dénomination d'un identifiant ................................................................................... 6
1.3. LES STRUCTURES DE PROGRAMME PL/SQL .................................................................................................. 7
1.3.1. Les blocs PL/SQL.................................................................................................................................. 7
1.3.2. Les structures de programmes PL/SQL................................................................................................. 8
1.3.3. Les règles syntaxiques des blocs PL/SQL ........................................................................................... 10
2. VARIABLES ET TYPES DE DONNEES..................................................................................................... 11
2.1. LES TYPES DE DONNEES PL/SQL ................................................................................................................ 11
2.1.1. Utilisation et traitement des variables ................................................................................................ 11
2.1.2. Les types de données scalaires............................................................................................................ 12
2.1.3. Les types de données composés........................................................................................................... 12
2.1.4. Les types de données LOB................................................................................................................... 13
2.2. LES VARIABLES SCALAIRES ......................................................................................................................... 13
2.2.1. Déclarer de variables scalaires .......................................................................................................... 13
2.2.2. Assigner des valeurs aux variables ..................................................................................................... 14
2.2.3. Déclarer des variables scalaires à l’aide de %TYPE ......................................................................... 14
2.3. LES VARIABLES COMPOSEES (LES COLLECTIONS)........................................................................................ 15
2.3.1. Les collections TABLE et VARRAY ..................................................................................................... 15
2.3.2. La collection RECORD ....................................................................................................................... 20
2.3.3. Des collections imbriquées.................................................................................................................. 23
2.4. LES VARIABLES NON-PL/SQL..................................................................................................................... 24
2.5. TRAITEMENT DES VARIABLES ET DES TYPES DE DONNEES PL/SQL............................................................. 25
2.5.1. Manipulation de valeurs à l’aide d’opérateurs................................................................................... 25
2.5.2. Manipulation de valeurs à l’aide de fonctions SQL ............................................................................ 26
2.5.3. Manipulation de valeurs à l'aide de fonctions PL/SQL....................................................................... 26
2.5.4. Conversion de types de données.......................................................................................................... 26
2.5.5. Portée des variables et blocs imbriqués.............................................................................................. 26
3. INTERACTION AVEC LE SERVEUR ORACLE...................................................................................... 28
3.1. EXTRACTION DE DONNEES .......................................................................................................................... 28
3.1.1. Extraire des données avec l'ordre SELECT…INTO............................................................................ 28
3.1.2. Exceptions engendrées par des instructions SELECT..INTO.............................................................. 29
3.2. MANIPULATION DES DONNEES .................................................................................................................... 29
3.2.1. Insertion de données ........................................................................................................................... 29
3.2.2. Mise à jour des données ...................................................................................................................... 30
3.2.3. Suppression de données ...................................................................................................................... 30
3.3. CURSEURS SQL .......................................................................................................................................... 31
3.3.1. Les caractéristiques des curseurs SQL ............................................................................................... 31
3.3.2. Attributs des curseurs SQL.................................................................................................................. 31
3.4. GESTION DES TRANSACTIONS ..................................................................................................................... 32
3.4.1. Validation des transactions en cours .................................................................................................. 32
3.4.2. Annulation des modifications en attente ............................................................................................. 32
3.4.3. Contrôle des points de transaction...................................................................................................... 32
4. LE CONTROLE DES FLUX DANS LES BLOCS PL/SQL ....................................................................... 34
4.1. LE CONTROLE CONDITIONNEL ..................................................................................................................... 34
4.1.1. Les actions à effectuer de façon sélective............................................................................................ 34
4.1.2. Les conditions booléennes................................................................................................................... 38

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

4.2. LES STRUCTURES DES BOUCLES : LE CONTROLE ITERATIF ........................................................................... 39


4.2.1. La boucle élémentaire LOOP.............................................................................................................. 39
4.2.2. La boucle FOR..LOOP........................................................................................................................ 41
4.2.3. La boucle WHILE..LOOP ................................................................................................................... 42
4.2.4. Les boucles imbriquées ....................................................................................................................... 43
5. LES CURSEURS EXPLICITES.................................................................................................................... 45
5.1. INTRODUCTION SUR LES CURSEURS ............................................................................................................. 45
5.1.1. Types de curseur ................................................................................................................................. 45
5.1.2. Les caractéristiques des curseurs explicites........................................................................................ 45
5.1.3. Contrôle des curseurs explicites ......................................................................................................... 45
5.2. UTILISATION DES CURSEURS EXPLICITES.................................................................................................... 46
5.2.1. Déclaration des curseurs explicites .................................................................................................... 46
5.2.2. Ouverture des curseurs explicites ....................................................................................................... 47
5.2.3. Extraction de données d’un curseur explicite ..................................................................................... 47
5.2.4. Fermeture d’un curseur ...................................................................................................................... 48
5.3. LES ATTRIBUTS DES CURSEURS EXPLICITES ................................................................................................ 48
5.3.1. Contrôle de l’état à l’aide de l’attribut %ISOPEN ............................................................................. 48
5.3.2. Contrôle de l’état à l’aide de l’attribut %FOUND ............................................................................. 49
5.3.3. Sortie d’une boucle à l’aide de l’attribut %NOTFOUND .................................................................. 49
5.3.4. Nombre de lignes renvoyées à l’aide de %ROWCOUNT.................................................................... 50
5.4. UTILISATION AVANCEE DES CURSEURS EXPLICITES ..................................................................................... 50
5.4.1. Extraction de lignes à l’aide de la boucle de curseur FOR ................................................................ 50
5.4.2. La boucle de curseur FOR avec une sous-requête.............................................................................. 51
5.4.3. Verrouiller et mettre à jour les lignes d'un curseur ............................................................................ 51
5.4.4. Déclaration de curseurs explicites avec des paramètres .................................................................... 52
5.4.5. Des curseurs avec des sous-requêtes .................................................................................................. 53
6. GESTION DES EXCEPTIONS ..................................................................................................................... 54
6.1. INTRODUCTION SUR LES EXCEPTIONS .......................................................................................................... 54
6.1.1. Lever et traiter les exceptions ............................................................................................................. 54
6.1.2. Les types d'exception........................................................................................................................... 54
6.2. CAPTURER LES EXCEPTIONS ........................................................................................................................ 55
6.2.1. Capturer les exceptions....................................................................................................................... 55
6.2.2. Capturer des erreurs prédéfinies du serveur Oracle .......................................................................... 55
6.2.3. Capturer des exceptions non prédéfinies du serveur Oracle .............................................................. 56
6.2.4. Les fonctions pour capturer les exceptions ......................................................................................... 58
6.2.5. Capturer les exceptions définies par l'utilisateur................................................................................ 58
6.2.6. La procédure RAISE_APPLICATION_ERROR .................................................................................. 59
6.3. LA PROPAGATION DES EXCEPTIONS ............................................................................................................. 61

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.

1.1.2. Les avantages du PL/SQL


o La modularisation du développement des programmes grâce aux :
- Blocs : regroupement en blocs des instructions entre lesquelles il existe un lien logique.
- Fonctions et procédures : imbrication de sous blocs à l’intérieur de blocs plus importants afin
d’élaborer des programmes puissants. Fractionnement d'un problème complexe en un
ensemble de modules logiques bien définis et simples à gérer. Ces modules peuvent être
ensuite mis en œuvre à l’intérieur de blocs.
- Packages : Regroupement des modules en une seule unité logique.

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 Structures de contrôle des langages procéduraux


- Les boucles : écriture de programmes avec des structures de contrôle issues des langages
procéduraux. Une séquence d’instructions peut donc être exécutée de façon conditionnelle ou
itérative dans une boucle.
- Les curseurs explicites : traitement de façon individuelle des lignes renvoyées par une
requête.
- Combinaison du PL/SQL avec des outils Oracle, tels que Oracle Developer (constitué de
Forms, Reports et Graphics), afin de regrouper les commandes associées, dans le but de
contrôler l’exécution.

o Traitement des erreurs


- Routine de traitement des exceptions : traitement des erreurs du serveur Oracle.
- Les exceptions définies par l'utilisateur : déclaration de conditions d’erreurs par l'utilisateur et
traitement des erreurs avec les routines de traitement des exceptions.

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.

o L’amélioration des performances


- PL/SQL peut être utilisé pour regrouper les ordres SQL ensemble en un seul bloc et d'envoyer
ce bloc au serveur en un seul appel, ce qui a pour conséquence de réduire le trafic sur le
réseau.
- Les performances dépendent de l’environnement d’exécution.

1.1.3. Les fonctionnalités du moteur PL/SQL


Un serveur Oracle prenant en charge PL/SQL est appelé serveur Oracle avec extension 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.

Figure 1 : Le moteur PL/SQL au niveau du serveur Oracle

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

Figure 2 : Le moteur PL/SQL des outils Oracle

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.

1.2.Conventions de programmation PL/SQL


1.2.1. La convention du code
S'écrivent en majuscule :
- les commandes SQL, tels que SELECT, INSERT…
- les mots clés PL/SQL, tels que DECLARE, BEGIN, IF…
- les types de données, tels que VARCHAR2, BOOLEAN…

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…

1.2.2. La convention de dénomination d'un identifiant


Afin de maintenir l’uniformité du code, un ensemble de préfixes et de suffixes a été développé afin de
distinguer facilement un identifiant parmi les autres identifiants tels que les objets de base de données
et les objets nommés.

Grâce à une convention de dénomination standard, le code est facile à lire et à mettre à jour.

Identifiant Convention de nommage Exemple


Variables v_name v_sal
Constantes c_name c_compagny
Curseurs name_cursor emp_cursor
Exceptions e_name e_too_many

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

Types Table name_table_type amount_table_type


Tables name_table order_table
Types Record name_record_type emp_record_type
Records name_record customer_record
Variables de substitution SQL*Plus p_name p_sal
Variables globales SQL*Plus g_name g_year_sal

(Voir aussi § 1.3.3 Règles syntaxiques des blocs PL/SQL)

1.3.Les structures de programme PL/SQL


1.3.1. Les blocs PL/SQL
PL/SQL est un langage structuré en blocs : les instructions entre lesquelles il existe un lien logique
sont regroupées en blocs.

Un bloc de base PL/SQL peut contenir trois sections :

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;

Æ La section déclarative de ce bloc déclare une variable de type VARCHAR2, d'une


longueur de 5 et appelée v_ename.
La section exécutable est constituée d'une seule instruction : un ordre SELECT qui

1.3.2. Les structures de programmes PL/SQL


Les structures de programmes sont des blocs ou des modules PL/SQL exécutant différentes fonctions
selon l’environnement d’exécution.
Une structure de programmes peut être constituée d’un bloc PL/SQL unique, de blocs imbriqués ou
d’un groupe de blocs.
Il existe plusieurs types de structures de programmes : les blocs anonymes, les procédures et
fonctions stockées, les procédures et fonctions d'application, les packages, les triggers de base de
données et les triggers d'application.

Les blocs anonymes

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 :

PL/SQL procedure successfully completed

Les procédures et fonctions stockées

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

FUNCTION name (parameters)


PROCEDURE nom (parameters) IS RETURN datatype IS
<déclaration> <déclaration>
BEGIN BEGIN
<instructions> <instructions>
[EXCEPTION] [EXCEPTION]
<traitement des exceptions> <traitement des exceptions>
END ; END ;

Une fonction, à la différence d'une procédure, retourne une valeur.

Il existe trois types de paramètres :


- IN : passer des valeurs à un sous-programme qui est appelé.
- OUT : retourner des valeurs à celui qui a appelé le sous-programme.
- INOUT : passer des valeurs initiales à un sous-programme et retourner la mise à jour des valeurs à
celui qui a appelé le sous-programme.

Les procédures et fonctions d'application

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 ;

CREATE PACKAGE BODY AS


PROCEDURE nom IS

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

Les triggers de base de données

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.

TRIGGER nom { BEFORE | AFTER } [FOR EACH ROW] [WHEN <condition>]


BEGIN
<instructions>
[EXCEPTION]
<traitement des exceptions>
END ;

Les triggers d'application

Il s’agit d’un bloc PL/SQL associé à un événement d’application et exécuté automatiquement


lorsqu’un événement spécifié se produit. Le trigger d'application n'est disponible que dans les
composants de Oracle Developper.

1.3.3. Les règles syntaxiques des blocs PL/SQL


Les règles générales de syntaxe appliquées au langage SQL le sont également au langage PL/SQL.

- Un identifiant peut comporter un maximum de 30 caractères et doit commencer par une lettre.

- Les mots réservés ne peuvent pas être utilisés comme identifiant.

- 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 mots clés ne doivent pas être coupés en fin de ligne.

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

variable_name [CONSTANT] datatype [NOT NULL] [ := | DEFAULT expr] ;

datatype : le type de données de la variable peut être scalaire, composé,


référence ou LOB.
CONSTANT : ce mot clé contraint la variable à contenir une valeur qui ne peut
être changée.
NOT NULL : ces mot clés contraignent la variable à contenir une valeur.
expr : l’expression définissant la valeur par défaut d’une variable peut
être une valeur littérale, une autre variable ou une expression
impliquant des opérateurs et des fonctions.

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.

Utilisation et traitement des variables :


- Déclarer et initialiser les variables dans la section déclarative.
Les déclarations allouent l'espace de stockage nécessaire pour une valeur, spécifient les types de
données et nomment la localisation du stockage qui sert à le référencer. Affecter de nouvelles
valeurs aux variables dans la section exécutable.
- Nommer les identifiants selon les règles utilisées pour la dénomination des objets SQL.
- Affecter une valeur initiale à une variable déclarée comme NOT NULL et/ou CONSTANT.
- Initialiser une variable avec une expression, en utilisant l’opérateur d’affectation " := " ou le mot
réservé DEFAULT. Par défaut, la valeur NULL est affectée aux variables.
- Passer les variables à des sous-programmes à l'aide de paramètres.

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 :

Scalaire Contient une valeur unique mais pas de composants internes.


Contient des composants internes qui peuvent être manipulés. Ce type de données est
réutilisable. Les variables de type composé sont des variables temporaires auxquelles
Composé
différentes valeurs peuvent être affectées au cours de l’exécution. Ex : types RECORD,
TABLE, NESTED TABLE et VARRAY.
Il s’agit d’un pointeur vers un autre type de données. Il contient des valeurs appelées
Référence
pointeurs, désignant d’autres objets programme.
Il s'agit d'un "localisateur" qui spécifie la localisation de gros objet (des images, des
LOB
vidéos…) qui sont stockés "out offline".

Il existe trois types de variables non-PL/SQL :


- les variables de substitution (cf Module 2 § 4.1 Les variables de substitutions)
- les variables définies par l'utilisateur (cf Module 2 § 4.2 Les variables définies par l'utilisateur)

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

- les variables hôtes (appelées aussi "bind" variable)

2.1.2. Les types de données scalaires


Un type de données scalaires est utilisé pour stocker une valeur unique. En PL/SQL, le type de
données scalaire est divisé en quatre catégories : nombre, caractères, date et booléen.

Les types scalaires les plus utilisés et leurs sous-types :

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.

2.1.3. Les types de données composés


Les types de données composés (appelées aussi collections) sont :

Type de données permettant de déclarer un identifiant pouvant stocker une


RECORD ligne constituée de plusieurs colonnes possédant chacune son propre nom et
son propre type de données.
Type de données permettant de déclarer un identifiant pouvant stocker au
TABLE plusieurs valeurs toutes du même type de données. Une TABLE n'a pas de
taille fixe et possède une colonne PRIMARY KEY.
Type de données permettant de déclarer un identifiant pouvant stocker au
plusieurs valeurs toutes du même type de données. Un tableau (VARRAY) a
VARRAY
une taille minimale fixée à 1 et une taille maximale fixée lors de sa
déclaration.

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

2.1.4. Les types de données LOB


Les types de données LOB (Large Object) d'Oracle8i, des blocs de données non structurés (tels que du
texte, des images, des fichiers vidéos et fichiers audios…) permettent de stocker des objets jusqu'à 4
gigaoctets dans la base de données.

Il existe quatre types de données LOB :

CLOB CLOB est utilisé pour stocker des gros blocs de


(Character Large Object Binary) texte (caractères sur 8 bits).
BLOB BLOB est utilisé pour stocker de larges objets
(Binary Large Object) binaires.
BFILE BFILE est utilisé pour stocker de larges objets
(Binary File) binaires tels que des fichiers OS.
NCLOB est utilisé pour stocker de gros blocs de
NCLOB
données, unité en octet ou multi-octets de taille
(National Language Character Large Object)
fixe.

2.2.Les variables scalaires


2.2.1. Déclarer de variables scalaires
Une variable doit être déclarée avant d'être référencée dans une instruction.

variable_name [CONSTANT] scalair [NOT NULL] [ := | DEFAULT expr] ;

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

2.2.2. Assigner des valeurs aux variables


Pour assigner une valeur à une variable, il faut écrire un ordre PL/SQL d'assignement. La variable doit
être explicitement nommée pour qu'elle reçoive la nouvelle valeur. Cette valeur est placé à gauche de
l'opérateur d'assignement " := ".

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 :

SQL> SELECT sal * 0.10


2 INTO v_bonus
3 FROM emp
4 WHERE empno = 7369 ;

Æ L'exemple ci-dessus sélectionne le salaire des employés dans la table EMP, le


majore de 10% et stocke le résultat dans la variable v_bonus.
La variable v_bonus peut être utilisée dans une expression ou sa valeur peut être
insérée dans une table de la base de données.

2.2.3. Déclarer des variables scalaires à l’aide de %TYPE


Lorsqu'une application doit mettre à jour les valeurs des colonnes d’une table, l'intégrité des données
doit être respectée et les erreurs d'exécution évitées. Les variables PL/SQL qui contiendront les
valeurs des colonnes doivent être déclarées du même type de données que les colonnes à mettre à
jour.

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.

variable_name table_name.column_name%TYPE [NOT NULL][ := | DEFAULT expr];

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

Æ La variable s’appelle v_ename. Le type de données de cette variable est celui de


la colonne ENAME de la table EMP.

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 ;

Æ En admettant que la colonne ENAME possède la contrainte NOT NULL, la


variable v_ename peut quand même posséder des valeurs nulles.

v_ename emp.ename%TYPE NOT NULL;

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

variable2 variable1%TYPE [NOT NULL] [ := | DEFAULT expr] ;

Exemple :

v_balance NUMBER(7,2) ;
v_min_balance v_balance%TYPE := 10 ;

Æ La variable v_min_balance est du même type que la variable v_balance, soit


NUMBER(7,2) et est initialisée à 10.

2.3.Les variables composées (les collections)


2.3.1. Les collections TABLE et VARRAY

Définir une collection TABLE

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

Æ Représentation graphique d'une table PL/SQL stockant des noms d'employés

La taille d’une table PL/SQL peut augmenter de façon dynamique.

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.

Déclaration d’un type TABLE PL/SQL :

TYPE type_name IS TABLE OF { column_type | variable%TYPE |


table.column%TYPE | table%ROWTYPE }
[NOT NULL]
[INDEX BY BINARY_INTEGER] ;

La clause INDEX BY est obligatoire en PL/SQL version 2 et optionnelle en PL/SQL


version 8. Les exemples de ce cours utilise la version 2 Si la clause INDEX BY est
omise, alors cela signifie que le type de la table est un type de table imbriqué dans
un autre.

Exemples :

TYPE table_type IS TABLE OF VARCHAR2(25)


INDEX BY BINARY_INTEGER ;

TYPE EmpList IS TABLE OF emp.empno%TYPE


INDEX BY BINARY_INTEGER ;

TYPE EmpTabTyp IS TABLE OF emp%ROWTYPE;


INDEX BY BINARY_INTEGER ;

Définir une collection VARRAY

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 :

TYPE type_name IS {VARRAY | VARYING ARRAY} {size_limit} OF


{column_type | variable%TYPE | table.column%TYPE |
table%ROWTYPE }
[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 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 :

TYPE Calendar IS VARRAY(366) OF DATE;

TYPE AnEntry IS RECORD (


term VARCHAR2(20),
meaning VARCHAR2(200));
TYPE Glossary IS VARRAY(250) OF AnEntry;

TYPE Platoon IS VARRAY(20) OF Soldier;


p1 Platoon;
p2 p1%TYPE;

CURSOR c1 IS SELECT * FROM dept;


TYPE DeptFile IS VARRAY(20) OF c1%ROWTYPE;

Déclarer et Initialiser une collection TABLE ou


VARRAY

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;

Le type de tableau CourseList a une capacité maximale de 20 postes.


Les quatre premiers postes du tableau my_courses sont initialisés dans la section
exécutive. La valeur NULL peut être passé au constructeur à condition que la
contrainte NOT NULL ne soit pas appliquée dans la déclaration du type VARRAY.
Un tableau VARRAY peut être initialisé de la même façon dans la section
déclarative, c'est le cas des tableaux my_courses2 et my_courses3. A la différence

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 :

CREATE TYPE CourseList AS VARRAY(50) OF VARCHAR2;


CREATE TABLE Student
( id_num INTEGER(4),
name VARCHAR2(25),
address VARCHAR2(35),
courses CourseList);

BEGIN
INSERT INTO Student
VALUES (5035, 'Mickey Mouse','122 Disney St',
CourseList('Eco','Geo','Hist','Eng','Math',...));
...

Le constructeur CourseList fournit une valeur pour le champ courses de la table de


base de données Student.

Interroger les collections TABLE et VARRAY

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

Référencer une collection TABLE ou VARRAY

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)

Æ Cette instruction référence le troisième élément d'une collection.

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;

Æ ename_table_type est un type de table PL/SQL indexée destiné à stocker des


valeurs du même type que la colonne ENAME de la table de base de données EMP.
hiredate_table_type est un type de table PL/SQL indexée destiné à stocker des
dates. ename_table est une table PL/SQL du type ename_table_type. hiredate_table
est une table PL/SQL du type hiredate_table_type.
Dans la section exécutable, la valeur "CAMERON" est stockée dans la table
ename_table à la ligne dont l'index vaut 1, et la valeur correspondant à la date du
jour additionnée de 7 jours est stockée dans la table hiredate_table à la ligne dont
l'index vaut 7. L'instruction IF teste si la ligne 1 existe dans la table ename_table. Si
l'élément existe, alors l'instruction INSERT INTO est exécutée.

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

Prepa1 := Prof; -- illegal ; différents types

IF Prepa2 = Prepa1 THEN -- compilation error


...
END IF;
...

2.3.2. La collection RECORD

Déclarer et définir une collection RECORD

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.

Déclaration d’un type RECORD :

TYPE type_record_name IS RECORD


( field_name1 { field_type | variable%TYPE | table.column%TYPE
table%ROWTYPE } [NOT NULL { := | DEFAULT}
expr],
field_name2 { field_type | variable%TYPE | table.column%TYPE }
table%ROWTYPE } [NOT NULL { := | DEFAULT} expr],
...) ;

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.

Déclaration d’un enregistrement du type RECORD :

Identifiant type_record_name ;

Les champs ne contenant aucune valeur sont initialisée automatiquement à NULL.

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.

Champ1 (type de données) Champ2 (type de données) Champ3 (type de données)


empno emp.empno%TYPE ename emp.ename%TYPE job emp.job%TYPE
7566 JONES MANAGER

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

Æ Cet enregistrement possède trois champs : empno, ename et job. Il s'agit de


l'employé numéro 7566 dont le nom est JONES et dont la fonction est MANAGER.

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 ;

Æ Le type RECORD emp_record_type est composé de trois champs : empno,


ename et job.
empno est un champ du même type de données que la colonne EMPNO de la table
EMP. ename est un champ du même type de données que la colonne ENAME de la
table EMP. job est un champ du même type de données que la colonne JOB de la
table EMP.
Les variables emp_record et emp_record2 sont ensuite déclarées du type
emp_record_type.

Un type RECORD peut être le composant d’un autre type RECORD, c’est à dire être imbriqué dans un
autre type RECORD.

Exemple :

TYPE time_type IS RECORD


( min SMALLINT,
hour SMALLINT ) ;

TYPE meeting_type IS RECORD


( day DATE,
place CHAR(20),
time time_type,
purpose CHAR(50)) ;

Æ Le RECORD meeting_type contient un type de données composé, time_type, un


type RECORD déclaré précédemment.

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

Déclarer une collection RECORD à l’aide de


%ROWTYPE

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

La structure de l’enregistrement déclaré sera identique à la structure de la table de base de données


spécifiée : l'enregistrement possèdera le même nombre de champs avec les mêmes noms et les mêmes
types de données que les colonnes de la table.
Un enregistrement peut également adopter la structure d'une ligne de données extraites d'un curseur.

Grâce à l'attribut %ROWTYPE :


- Il n’est pas nécessaire de connaître le nombre de colonnes et le type de données des colonnes
sous-jacentes.
- Le type de données des champs de l’enregistrement sera modifié en conséquence lors de
l’exécution et sera automatiquement modifier si le type d'une colonne change.

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;

Æ Grâce à l’attribut %ROWTYPE, la variable emp_record est un enregistrement qui


possède la même structure (même colonnes, même types de données) que la table
EMP.

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.

Référencer et initialiser une collection RECORD

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

Æ Cette instruction référence le champ job de l'enregistrement emp_record.

emp_record.job := 'CLERK' ;

Æ Cette instruction affecte la valeur "CLERK" au champ job de l'enregistrement


emp_record.

Les instructions SELECT..INTO (§ 3.1.1 Extraction de données à l'aide la clause SELECT..INTO) et


FETCH (§ 5.2.3 Extraction de données d'un curseur explicite) permettent d'affecter, en une seule
instruction, une valeur à chaque colonne d'un enregistrement. Les noms des colonnes doivent
apparaître dans le même ordre que les champs de l'enregistrement
Un champ d'un enregistrement peut être assigné à un champ d'un autre enregistrement à condition
qu'ils aient le même type de données.
Un enregistrement défini par l'utilisateur et un enregistrement défini avec l'attribut %ROWTYPE
n'aura jamais le même type de données.

2.3.3. Des collections imbriquées


Une table d'enregistrements permet de stocker de façon dynamique des enregistrements dans une table.
Une table d'enregistrements est constituée de deux colonnes : une colonne clé primaire et une colonne
de type RECORD.

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

Pour référencer un champ dans une table PL/SQL :

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;

Æ La première instruction de la section exécutable affecte la valeur "CLERK" au


champ job de la ligne indexée à 2 de la table dept_table.

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

2.4.Les variables non-PL/SQL


Il existe trois types de variables non-PL/SQL :
- les variables de substitution (cf Module 2 § 4.1 Les variables de substitutions)
- les variables définies par l'utilisateur (cf Module 2 § 4.2 Les variables définies par l'utilisateur)
- les variables hôte (appelées aussi "bind" variable)

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.

Déclarer une variable hôte :

VAR[IABLE] variable_name data_type

La longueur de la variable devra être précisé pour les types de chaîne de caractères.

Exemple :

SQL> VARIABLE return_code NUMBER


SQL> VARIABLE return_msg VARCHAR2(30)

Le SQL et l'environnement SQL*Plus peuvent référencer les variables hôtes.

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

Pour les chaînes de caractères :

'&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

VARIABLE g_monthly_sal NUMBER


ACCEPT p_annual_sal PROMPT 'Please enter the annual salary : '
DECLARE
v_sal NUMBER(9,2) := &p_annual_sal;
BEGIN
:g_monthly_sal := v_sal/12;
END;
/
PRINT g_monthly_sal

g_monthly_sal est une variable hôte référencée avec (:).


p_annual_sal est une variable de substitution référencée apr (&).
A l'exécution du bloc, le moteur PL/SQL demandera la saisie de la variable
p_annual_sal. Sa valeur sera divisée par 12, le résultat sera stocké dans la variable
g_monthly_sal.

2.5.Traitement des variables et des types de données


PL/SQL
2.5.1. Manipulation de valeurs à l’aide d’opérateurs
Il existe quatre types d'opérateurs utilisés en PL/SQL :
- les opérateurs logiques
- les opérateurs arithmétiques
- les opérateurs de concaténations
- l'opérateur exponentiel
Les trois premiers types d'opérateurs sont les mêmes qu'en SQL.
(cf. cours Oracle SQLP "Module 1 : Ordres SELECT basiques", le paragraphe 2.1.4 "Les expressions
arithmétiques", le paragraphe 2.2.2 "L'opérateur de concaténation", le paragraphe 3.2 "Les opérateurs
de comparaison", le paragraphe 3.3 "Les opérateurs logiques")

Ordre d'évaluation des opérateurs utilisés en PL/SQL:

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

Æ (v_n1 = v_n2) retourne une valeur booléenne affectée à v_value. Si v_value ne


contient pas la valeur NULL, alors v_valid contiendra TRUE. Au contraire, si v_value
contient la valeur NULL, alors v_valid contiendra FALSE.

Comme dans SQL, l'ordre dans lequel les opérations sont effectuées peut être contrôlé à l'aide de
parenthèses.

2.5.2. Manipulation de valeurs à l’aide de fonctions SQL


Voici des fonctions SQL valides dans des expressions PL/SQL :

- Fonctions mono-ligne alphanumériques :


LOWER(), SUBSTR(), LENGTH()

- Fonctions mono-ligne numériques :


ROUND(), TRUNC()...

- Fonctions de conversion de type de données :


TO_CHAR(), TO_DATE(), TO_NUMBER()...

- Fonctions portant sur les dates :


ADD_MONTH(), ADD_DAY()...

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

2.5.3. Manipulation de valeurs à l'aide de fonctions PL/SQL


P17-8

2.5.4. Conversion de types de données


Les variables concaténées dans une expression doivent être du même type de données.
Les fonctions de conversion sont utilisées afin d'éviter qu'une expression ne contienne des types de
données différents.

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.

2.5.5. Portée des variables et blocs imbriqués


L’avantage de PL/SQL par rapport à SQL est la prise en charge des blocs imbriqués. Un bloc peut
être imbriqué à n’importe quel endroit où une instruction exécutable est autorisée. Le bloc imbriqué
fonctionne comme une instruction. La partie exécutable d’un bloc peut donc être divisée en blocs plus
petits.
La section de traitement des exceptions peut également contenir des blocs 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 27 / 63

Le fractionnement de la partie exécutable en blocs plus petits facilite la modularisation et la possibilité


de réutilisation du code. Le code est ainsi mieux structuré.

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 ;

La section de traitement des exceptions peut contenir des blocs imbriqués.

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

3. Intéraction avec le serveur oracle


3.1.Extraction de données
3.1.1. Extraire des données avec l'ordre SELECT…INTO
Pour traiter les données stockées dans une table de la base de données, les données doivent d'abord
être extraites de la table et ensuite placées dans des variables PL/SQL. Cette opération peut être
effectuée facilement à l’aide de l’instruction SELECT..INTO. Cette instruction place les valeurs issues
de l'ordre SELECT dans des variables.

SELECT select_list
INTO { variable_name [variable_name,...] | record_name }
FROM table_list
[WHERE condition] ;

select_list spécifie la liste des colonnes à extraire d’une table de base de


données. Elle peut contenir des expressions SQL, des fonctions de ligne ou des
fonctions de groupes.
variable_name est une variable scalaire destine à stocker une valeur récupérée
par la requête. Les variables booléennes ne sont pas admises.
record_name est un enregistrement destiné à stocker toutes les valeurs récupérées
par la requête.
table_list spécifie la liste des tables intervenant dans la requête.
condition est la ou les conditions de la requête qui peuvent être composées de
noms de colonnes, d'expressions, de constantes, d'opérateurs de comparaison, des
variables et constantes PL/SQL.

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 ;

Æ Les colonnes date_ordered et date_shipped sont extraites de la table S_ORD et


leurs valeurs sont respectivement placées dans les variables scalaires
v_date_ordered et v_date_shipped.

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 ;

Æ dept_record est un enregistrement dont la structure est identique à la structure


d'une ligne de la table DEPT. L'instruction SELECT..INTO retourne les
enregistrements de la table DEPT et les stocke dans l'enregistrement det_record.

3.1.2. Exceptions engendrées par des instructions SELECT..INTO


Les erreurs d’exécution dues à des erreurs de codage interrompent le traitement normal. Une erreur
provoquant l’arrêt d’un bloc PL/SQL est appelée une exception.
Une exception peut également être produite lors de l’extraction de données d’une table de base de
données à l’aide de l’instruction SELECT..INTO. L’instruction SELECT ne doit extraire qu'une seule
ligne, sinon une exception se produit.

Les deux exceptions SELECT pouvant être produites sont :

Cette exception se produit lorsque l’instruction SELECT retourne plus


TOO_MANY_ROWS d’une ligne. Le serveur Oracle attribue le numéro d’erreur 1422 à cette
exception.
Cette exception se produit lorsque l’instruction SELECT ne retourne
NO_DATA_FOUND aucune ligne. Le serveur Oracle attribue le numéro d’erreur +1403 à cette
exception.

Les exceptions produites peuvent être traitées à l’aide de routines de traitements d’exceptions.

3.2.Manipulation des données


3.2.1. Insertion de données
L’instruction INSERT est une commande du langage de manipulation des données. Elle est utilisée
pour ajouter de nouvelles lignes dans une table.

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

INSERT INTO table_name [(column1, column2, ...)]


VALUES (variable1, variable2, ...);

L'instruction INSERT a le même fonctionnement qu’en SQL.

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 ;

Æ La valeur de la clé primaire empno est obtenue à partir de la pseudo colonne


NEXTVAL de la séquence empno_sequence.

3.2.2. Mise à jour des données


L’instruction UPDATE modifie les données existantes de la table. Il s’agit d’une instruction du
langage de manipulation des données (DML).

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.

3.2.3. Suppression de données


L’instruction DELETE supprime des lignes dans une table.

DELETE FROM table_name


[WHERE condition] ;

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 ;

Æ L'employé portant le numéro 1234 est supprimé de la table EMP.

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.

3.3.2. Attributs des curseurs SQL


Les résultats d’un curseur SQL peuvent être évalués à l’aide d’attributs de curseurs SQL.

Il existe quatre attributs des curseurs SQL :

SQL%ROWCOUNT Nombre de lignes affectées par la dernière instruction SQL.


Retourne TRUE si la dernière instruction SQL a retourné une ou plusieurs
SQL%FOUND
lignes.
SQL%NOTFOUND Retourne TRUE si la dernière instruction SQL n’a retourné aucune ligne.
Détermine si un curseur est ouvert. Il prend toujours la valeur FALSE, car
SQL%ISOPEN
PL/SQL ferme les curseurs implicites immédiatement après leur exécution.

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 :

VARIABLE rows_deleted VARCHAR2(30)


DECLARE
v_ordid NUMBER := 605;
BEGIN
DELETE FROM item
WHERE ordid = v_ordid;
: rows_deleted := (SQL%ROWCOUNT || ' rows deleted. ');
END;
/
PRINT rows_deleted

Æ 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

3.4.Gestion des transactions


3.4.1. Validation des transactions en cours
Toutes les modifications ou transactions en cours apportées aux enregistrements de bases de données
sont temporaires, et ne sont pas écrites immédiatement dans la base de données. Ces modifications
sont stockées dans une zone de mémoire appelée database buffer cache.
La commande SQL COMMIT sert à valider les modifications en cours apportées aux données de la
base. La commande SQLCOMMIT confirme la transaction en cours en la rendant permanente dans la
base de données.

COMMIT [WORK] ;

Exemple :

DECLARE
v_deptno emp.deptno%TYPE := 50 ;
BEGIN
DELETE FROM emp
WHERE deptno = v_deptno ;
COMMIT ;
END ;

Æ Les employés appartenant au département n°50 sont supprimés de la table EMP.


La commande COMMIT rend la suppression des lignes permanente.

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)

3.4.2. Annulation des modifications en attente


La commande ROLLBACK permet d’annuler les modifications en attente d'être validées. Grâce à
cette commande, les modifications stockées dans la zone de mémoire database buffer cache sont
annulées avant la mise à jour de la table.

ROLLBACK [WORK] ;

Exemple :

DECLARE
v_deptno emp.deptno%TYPE := 50 ;
BEGIN
DELETE FROM emp
WHERE deptno = v_deptno ;
ROLLBACK ;
END ;

Æ Les employés appartenant au département n°50 sont supprimés de la table EMP.


La commande ROLLBACK annule les modifications apportées à la table EMP.

3.4.3. Contrôle des points de transaction


La commande SAVEPOINT associée à la commande ROLLBACK permet d’annuler les
modifications en attente à partir d’un point donné.
Elle est utilisée pour créer un marqueur dans la transaction afin d’enregistrer les modifications jusqu’à
un point donné. La commande ROLLBACK est utilisée ultérieurement pour faire référence au
marqueur afin d’annuler une partie de la transaction.

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 ;

ROLLBACK TO SAVEPOINT marqueur ;

Exemple :

BEGIN
INSERT INTO temp (num_col1, num_col2, char_col)
VALUES (1, 1, ‘ROW 1’);

SAVEPOINT a;

INSERT INTO temp (num_col1, num_col2, char_col)


VALUES (2, 1, ‘ROW 2’);

SAVEPOINT b;

INSERT INTO temp (num_col1, num_col2, char_col)


VALUES (3, 1, ‘ROW 3’);

SAVEPOIINT c;

ROLLBACK TO SAVEPOINT b;
END ;

Æ Le troisième ordre INSERT est annulé.

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

4. Le contrôle des flux dans les blocs


PL/SQL
4.1.Le contrôle conditionnel
4.1.1. Les actions à effectuer de façon sélective
Le flux logique des ordres peut être changé en utilisant un ordre conditionnel IF et des structures de
contrôle de boucle.

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 ;

condition est une variable booléenne ou une expression booléenne associée à


une séquence d'ordres qui sont exécutés seulement si le résultat de l'expression ou
la variable est vrai.
THEN est une clause qui associe la condition qui la précède avec la séquence
d'ordres qui la suit.
statements : les instructions peuvent être des ordres SQL et PL/SQL.
ELSIF est une clause suivie d'une condition. La clause ELSIF est utilisée si la
condition précédente est fausse.
ESLE est une clause suivie d'une séquence d'ordres. La clause est utilisée si toutes
les conditions qui la précèdent sont fausses.

Il existe trois formes d'ordre IF :


- IF-THEN-END IF
- IF-THEN-ELSE-END IF
- IF-THEN-ELSIF-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.

IF condition THEN instructions ;

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

Figure 3 : Algorithme de l'ordre IF-THEN-END IF

Exemple :

...
IF v_ename = 'MILLER' THEN
v_job := 'SALESMAN' ;
v_deptno := 30 ;
v_new_comm := sal * 0.20 ;
END IF ;
...

Æ Cette ordre IF attribue la fonction de SALESMAN, le département 35 et une


commission de 20% du salaire actuel si le nom de l'employé est Miller.

La boucle IF peut contenir d'autres boucles IF, par exemple :

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 ;

Il ne peut y avoir qu'une seule clause ELSE

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

Figure 4 : Algorithme de l'ordre IF-THEN-ELSE-END IF

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.

Il ne peut y avoir q'une seule clause

Exemple :

...
IF v_ename = 'KING' THEN
v_job := 'MANAGER';
ELSE
v_job := 'CLERK';
END IF;
...

Æ Cette ordre IF attribue la fonction de Manager à l'employé KING et la fonction


Clerk aux autres employés.

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 ;

Figure 5 : Algorithme de l'ordre IF-THEN-ELSIF-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

Æ Cette ordre IF attribue une commission de $5000 aux employés du


département 10, une commission de $7500 aux employés du département 20
et une commission de $2000 aux autres employés.

La syntaxe de l’instruction IF est dictée par deux règles :


- le mot clé ELSIF représente un seul mot et le mot clé END IF est composé de deux mots,
- l’instruction IF peut comporter plusieurs clauses ELSIF mais uniquement une seule clause
ELSE.

Remarque : l'ordre GOTO p19-3

4.1.2. Les conditions booléennes


Les conditions booléennes peuvent être simples ou complexes.
Une condition booléenne simple est la combinaison d'expressions avec un opérateur de comparaison.

Exemple :

v_sal > 1000

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_sal > 1000) AND (v_sal = (v_comm * 4))

v_result := (v_tag1 AND v_tag2)

AND TRUE FALSE NULL


TRUE TRUE FALSE NULL
FALSE FALSE FALSE FALSE
NULL NULL FALSE NULL

v_result := (v_tag1 OR v_tag2)

OR TRUE FALSE NULL


TRUE TRUE TRUE TRUE
FALSE TRUE FALSE NULL
NULL TRUE NULL NULL

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

4.2.Les structures des boucles : le contrôle itératif


4.2.1. La boucle élémentaire LOOP
Les instructions de contrôle itératif sont utilisées pour exécuter plusieurs fois une instruction ou une
séquence d’instructions.
La boucle élémentaire est constituée d’un ensemble d’instructions incluses entre les délimiteurs LOOP
et END LOOP. Ces instructions sont exécutées de façon répétée.

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.

EXIT en tant qu'action EXIT en tant qu'instruction autonome


dans une instruction IF : dans la boucle :

LOOP LOOP
statement1 ; statement1 ;
statement2 ; statement2 ;
… …
statementN ; statementN ;

IF condition THEN EXIT EXIT [WHEN condition] ;


; END LOOP ;
END LOOP ;

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

Figure 6 : Algorithme du boucle LOOP avec une condition de sortie


La boucle s'arrête lorsque la condition de sortie est vraie. Si la condition est placée à la fin de la
boucle, les instructions seront exécutées au moins une fois. Si la condition est placée au début de la
boucle et que cette condition est vraie, alors aucunes instructions associées à la boucle n'est exécutées.

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.

4.2.2. La boucle FOR..LOOP


La boucle FOR est un mécanisme permettant d’exécuter un ensemble d’instructions un certain nombre
de fois dans une boucle.
La boucle FOR..LOOP a la même structure générale que la boucle basique LOOP. FOR..LOOP
possède, en plus, un ordre de contrôle placé avant le mot clé LOOP qui détermine le nombre
d'itération que PL/SQL doit effectuer.

FOR index IN [REVERSE] lower_limit..higher_limit


LOOP
statements ;
END LOOP ;

REVERSE déclenche une décrémentation (au lieu d'une incrémentation) du compteur


(index) de 1 à chaque itération de la boucle jusqu'à ce que la limite inférieure soit
atteinte.

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.

Les règles à respecter concernant l’utilisation de la boucle FOR :


- Ne faire référence à l’index qu’à l’intérieur de la boucle, car il n’est pas défini en dehors de
celle-ci.
- Les références à la valeur existante d’un index doivent être effectuées dans une expression. La
valeur précédente d’un index ne peut pas être référencée.
- La référence à l’index ne peut pas être une cible d’affectation.
index := value ; Æ code non valide

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

Figure 7 : Algorithme de la boucle FOR

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.

4.2.3. La boucle WHILE..LOOP


La boucle WHILE exécute des instructions tant que sa condition est vraie.

WHILE condition
LOOP
statement1 ;
statement2 ;

statementN ;
END LOOP ;

La condition est évaluée au démarrage de chaque itération.


La boucle se termine lorsque la condition est fausse. Si la condition est fausse au démarrage de la
première itération, aucune itération n’a lieu et le contrôle sort de la boucle.
Si la condition est nulle, la séquence d'instructions de la boucle n'est pas exécutée et le contrôle passe à
l'ordre suivant : l'instruction END LOOP.

La boucle WHILE peut posséder un compteur (un index) explicite.

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

Figure 8 : Algorithme de la boucle WHILE

Exemple :

ACCEPT p_new_order PROMPT 'Enter the order number : '


ACCEPT p_item PROMPT 'Enter the number of items in this order : '
DECLARE
v_count NUMBER(2) := 1;
BEGIN
WHILE v_count <= &p_items
LOOP
INSERT INTO item (ord_id, item_id)
VALUES (v&p_new_order, v_count);
v_count := v_count+1;
END LOOP;
END ;

Æ L'utilisateur saisit le numéro d'ordre (p_new_order) et un nombre de lignes à


insérer pour ce numéro d'ordre (p_item). La boucle WHILE insère le nombre de ligne
défini par l'utilisateur (p_item). Ces lignes insérées auront pour identifiant la valeur
courante de v_count et pour numéro d'ordre p_new_order. Les insertions dans la
table s'arrêtent lorsque le compteur v_count est supérieur à p_item.

4.2.4. Les boucles imbriquées


Une boucle imbriquée est une boucle intégrée dans une autre. La boucle contenant une autre boucle est
appelée boucle externe. La boucle imbriquée est appelée boucle interne.
Les boucles peuvent être imbriquées à plusieurs niveaux. Les boucles FOR peuvent être imbriquées
dans des boucles WHILE et inversement.

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

5. Les curseurs explicites


5.1.Introduction sur les curseurs
5.1.1. Types de curseur
Les curseurs permettent de nommer des zones de mémoire SQL privée et d’accéder ainsi aux
informations qui y sont stockées lors de l’exécution d’une instruction SQL.
Il existe deux types de curseurs : les curseurs implicites (ou curseurs SQL) et explicites.

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.

5.1.2. Les caractéristiques des curseurs explicites


Les curseurs explicites sont déclarés par l’utilisateur et sont utilisés pour traiter les résultats d’une
requête qui retournent plusieurs lignes.

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.

Les curseurs explicites peuvent être contrôlés manuellement par le programmeur.

5.1.3. Contrôle des curseurs explicites


Le contrôle d’un curseur est le processus de création et d’utilisation d’un curseur.

Le contrôle des curseurs a lieu en quatre étapes :

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

- Accès aux données du curseur :


Une fois un curseur explicite déclaré et ouvert, le résultat de la requête du curseur peut être
accédé. L’instruction FETCH est utilisée pour extraire une ligne à la fois de l’ensemble actif.

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.

Figure 9 : Le contrôle des curseurs explicites à l'aide de quatre commandes

5.2.Utilisation des curseurs explicites


5.2.1. Déclaration des curseurs explicites
Un curseur est déclaré dans la section déclarative à l’aide de l’instruction CURSOR.

CURSOR cursor_name IS
Select_statement ;

Un curseur doit être déclaré, nommé et associé à une requête.


La requête peut contenir des variables préalablement déclarées, mais en aucun cas de clause INTO.

Exemple :

DECLARE
CURSOR emp_cursor IS
SELECT empno, sal * 10
FROM emp;

CURSOR dept_cursor IS
SELECT *
FROM dept
WHERE deptno = 10 ;
BEGIN
...
END ;

Æ Le curseur explicite nommé emp_cursor stocke les valeurs du champ empno de


la table EMP et le résultat de la multiplication du champ sal de la table EMP par 10.
Le curseur explicite nommé dept_cursor stocke les enregistrements de la table DEPT
dont le numéro de département est 10.

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

5.2.2. Ouverture des curseurs explicites


L’ouverture d’un curseur exécute la requête associée au curseur et identifie l'ensemble actif.

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.

5.2.3. Extraction de données d’un curseur explicite


L’instruction FETCH est utilisée pour extraire une par une les lignes de l'ensemble actif.

FETCH cursor_name INTO {variable1 [,variable2…] | record_name} :

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

Æ Le curseur emp_cursor sélectionne tous les numéros et noms des employés de la


table EMP. La boucle FOR et l'instruction FETCH permettent de récupérer un par un
les dix premiers employés sélectionnés par le curseur.

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

5.2.4. Fermeture d’un curseur


L'instruction CLOSE est utilisée pour fermer le curseur.

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

5.3.Les attributs des curseurs explicites


Comme dans le cas des curseurs implicites, quatre attributs permettent d’obtenir les informations
relatives à l’état d’un curseur explicite : %ISOPEN, %FOUND, %NOTFOUND et%ROWCOUNT.
Ces attributs ne peuvent pas être utilisés dans des ordres SQL.

5.3.1. Contrôle de l’état à l’aide de l’attribut %ISOPEN


L’attribut %ISOPEN est un attribut booléen qui prend la valeur TRUE si le curseur est ouvert. Si
FALSE est le résultat de l’attribut %ISOPEN, le curseur peut être ouvert.
L’ajout du mot clé NOT inverse la condition.

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 ;

Æ L'instruction IF ouvre le curseur emp_cursor si ce dernier est fermé afin que


l'instruction FETCH qui suit n'échoue pas.

5.3.2. Contrôle de l’état à l’aide de l’attribut %FOUND


%FOUND est un attribut de type booléen qui prend la valeur TRUE si l’opération d’accès la plus
récente a renvoyé une ligne. Lorsque aucune ligne n’est renvoyée, l’attribut prend la valeur FALSE.

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.

5.3.3. Sortie d’une boucle à l’aide de l’attribut %NOTFOUND


%NOTFOUND est un attribut booléen qui prend la valeur TRUE si l’opération d’accès la plus récente
ne renvoie aucune ligne. Si une ligne est renvoyée, l’attribut prend la valeur FALSE.

cursor_name%NOTFOUND

Avant le premier ordre FETCH, l'attribut %NOTFOUND est évalué à NULL.

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 ;

Æ La boucle LOOP et l'instruction FETCH permettent d'extraire les lignes de


l'ensemble actif de emp_cursor jusqu'à ce que plus aucunes lignes ne soit trouvées.

5.3.4. Nombre de lignes renvoyées à l’aide de %ROWCOUNT


%ROWCOUNT est un attribut numérique qui prend la valeur du nombre total de lignes accédées
jusqu’alors dans une boucle.

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 ;

Æ La boucle LOOP et l'instruction FETCH permettent d'extraire les cinq premières


lignes de l'ensemble actif de emp_cursor.

5.4.Utilisation avancée des curseurs explicites


5.4.1. Extraction de lignes à l’aide de la boucle de curseur FOR
La boucle de curseur FOR permet d'extraire et de traiter une par une les lignes de l'ensemble actif.

FORrecord_name IN cursor_name
LOOP
statements ;
END LOOP ;

La boucle de curseur FOR ouvre et ferme automatiquement le curseur.


De plus, il n’est plus nécessaire de déclarer l'enregistrement PL/SQL contrôlant la boucle
(record_name) , celui-ci est déclaré implicitement par le boucle de curseur FOR.

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.

5.4.2. La boucle de curseur FOR avec une sous-requête


Une requête peut être définie au début de la boucle. La requête est appelée un sous-ordre SELECT ou
une sous-requête, le curseur est interne à la boucle FOR et ne possède donc pas de nom. Les attributs
ne peuvent pas être testés sur ce type de curseur, car il ne possède pas de nom.

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;

5.4.3. Verrouiller et mettre à jour les lignes d'un curseur


La clause WHERE CURRENT OF permet de mettre à jour ou de supprimer la dernière ligne accédée
(la ligne courante) d'un curseur. Cette clause est utilisée dans les ordres SQL UPDATE et DELETE
dans la section exécutable.

WHERE CURRENT OF cursor_name

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

column_reference précise la colonne de la table dont les valeurs sélectionnées par la


requête sont à verrouiller. (Il peut s'agir d'une liste de colonnes)
Le mot clé NOWAIT permet de retourner une erreur Oracle si le verrou porte sur des
lignes déjà verrouillées par une autre session.

La clause FOR UPDATE est la dernière clause d'un ordre SELECT.


Un curseur possédant la clause FOR UPDATE ne peut plus être interroger après validation.

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 ;

Æ WHERE CURRENT OF permet de mettre à jour la dernière ligne accédée dans le


curseur emp_cursor.

5.4.4. Déclaration de curseurs explicites avec des paramètres


Il est possible d’utiliser le même curseur dans différentes situations et d’extraire des données
différentes chaque fois. Pour cela, des paramètres sont passés au curseur autorisant ainsi l’exécution de
la requête pour différentes valeurs. Un curseur avec des paramètres aboutit à des ensembles actifs
différents suivant les paramètres passés au curseur.

CURSOR cursor_name [(parameter [IN] datatype [{:= | DEFAULT} expr, …)] IS


select_statement ;

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.

OPEN cursor_name (value,...)


Ou

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

FOR record_name IN cursor_name(value,...)


LOOP
...
END LOOP;

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 ;

Æ Le curseur prend en paramètre deux variables scalaires p_job et p_deptno. Le


curseur sélectionne les enregistrements relatifs aux employés exerçant la fonction
ANALYST passée en paramètre au curseur et travaillant dans le département 20
également passé en paramètre.

5.4.5. Des curseurs avec des sous-requêtes


La requête associée à un curseur peut être composée, tout comme une requête traditionnelle, d'une ou
plusieurs sous-requêtes. (cf Module 2 : Récupération de données …)

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

6. Gestion des exceptions


6.1.Introduction sur les exceptions
Une exception est un identificateur ("identifier") en PL/SQL qui est levée durant l'exception.
Lorsqu'une exception survient dans la section des commandes exécutables, le contrôle de l'exécution
quitte immédiatement cette section et recherche dans la section de gestion des exceptions une
exception correspondant à l'erreur rencontrée.

6.1.1. Lever et traiter les exceptions


Il existe deux façons de lever une exception :
- Une erreur Oracle survient et l'exception associée est automatiquement levée. Par exemple, si
aucune ligne n'est retournée dans un ordre SELECT, l'erreur ORA-01403 survient, alors le
langage PL/SQL lève l'exception NO_DATA_FOUND.
- Le programmeur lève une exception explicitement en utilisant l'ordre RAISE dans un bloc.
L'exception levée doit être une exception définie par le développeur ou une exception
prédéfinie.
-
Il existe deux façons de traiter une exception :
- L'attraper (la capturer) avec un traitement ("handler").
- La propager dans l'environnement.

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.

6.1.2. Les types d'exception


Il existe trois types d'exception :
- Les erreurs du serveur Oracle prédéfinies
- Les erreurs du serveur Oracle non prédéfinies
- Les erreurs définies par le développeur

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

6.2.Capturer les exceptions


6.2.1. Capturer les exceptions
Le développeur peut capturer n'importe quel erreur en incluant une routine correspondante dans la
section de gestion des exceptions d'un bloc PL/SQL. Chaque section de traitement (appelé "handler")
est constitué d'une clause WHEN qui spécifie une exception, suivie d'une séquence d'ordres exécutée
lorsque l'exception est levée.

Syntaxe :

EXCEPTION
WHEN exception1 [OR exception2...] THEN
statement1;
statement2;
...
[WHEN exception3 [OR exception4...] THEN
statement1;
statement2;
...]
[WHEN OTHERS THEN
statement1;
statement2;
...]

exception représente le nom standard d'une exception prédéfinie ou le nom d'une


exception définie par le développeur déclarée dans la section déclarative.
statement représente un ou plusieurs ordres SQL ou PL/SQL.
OTHERS est une clause optionnelle dans la gestion des exceptions qui capture les
exceptions non spécifiées dans les clauses WHEN précédentes. Cette clause doit
être la dernière zone de traitement d'exception et ne doit apparaître qu'une seule
fois. (Certains outils d'Oracle possèdent leurs propres exceptions qui peuvent être
soulevées. La clause OTHERS peut capturer ces exceptions).

6.2.2. Capturer des erreurs prédéfinies du serveur Oracle


Pour capturer une erreur prédéfinie par le serveur Oracle, son nom doit être référencé dans la routine
de traitement des exceptions.

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

Tableaux des exceptions prédéfinies :

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

6.2.3. Capturer des exceptions non prédéfinies du serveur Oracle


Pour capturer une exception non prédéfinie du serveur Oracle, il existe deux méthodes. La première
consiste à utiliser la clause OTHERS dans la section de gestion des exceptions. La deuxième permet
un traitement personnalisé de l'exception :
1. Déclarer l'exception dans la section déclarative.(L'exception déclarée est implicitement levée)
Syntaxe :

exception EXCEPTION;

exception est le nom de l'exception donné par le développeur.

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 :

PRAGMA EXCEPTION_INIT(exception, error_number);

exception correspond à l'exception déclarée précédemment.


error-number est un numéro d'erreur standard du serveur Oracle.

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.

3. Référencer l'exception dans une routine de la section de gestion des exceptions.


Syntaxe :

WHEN exception THEN


statement1;
statement2;
...

exception correspond à l'exception déclarée et associée à un numéro d'erreur


précédemment.
statement correspondent aux ordres PL/SQL traitant l'exception.

Déclarer Associer Référencer

Section de gestion
Section déclarative des exceptions

Figure 1 : Capturer des exceptions non prédéfinies du serveur Oracle

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.

6.2.4. Les fonctions pour capturer les exceptions


Lorsqu'une exception se produit, le code de l'erreur associé à l'exception et le message d'erreur peuvent
être récupérés avec deux fonctions :
SQLCODE retourne le numéro d'erreur Oracle d'une exception interne. La valeur retournée
peut être assignée à une variable de type NUMBER.
- SQLERRM retourne le message associé au numéro de l'erreur. La valeur retournée peut être
assignée à une variable de type chaîne de caractères.

En générale, SQLCODE retourne un nombre négatif.


Quelques valeurs particulières retournées par SQLCODE :
- Si SQLCODE retourne 0, cela signifie qu'aucune exception n'a été levée ("encountered").
- Si SQLCODE retourne 1, cela signifie que l'exception levée a été définie par l'utilisateur.
- Si SQLCODE retourne +100, cela signifie que l'exception levée est l'exception prédéfinie
NO_DATA_FOUND.

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;

Ce bloc PL/SQL récupère le numéro et le message de l'erreur par l'intermédiaire de


deux variables, puis stocke leurs valeurs dans la table ERRORS.

6.2.5. Capturer les exceptions définies par l'utilisateur


Le langage PL/SQL permet à l'utilisateur de définir ses propres exceptions. Les exceptions définies par
l'utilisateur doivent être :
1. déclarées dans la section déclarative d'un bloc PL/SQL.
Syntaxe :

exception EXCEPTION;

exception est le nom de l'exception donné par le développeur.

2. levées explicitement dans la section exécutable avec l'ordre RAISE.


Syntaxe :

RAISE exception;

exception est le nom de l'exception déclarée par le développeur.

3. référencées avec dans une routine de la section de gestion des 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 59 / 63

Syntaxe :

WHEN exception THEN


statements;

exception est le nom de l'exception déclarée et levée explicitement précédemment.

Déclarer Lever Référencer

Section Section Section de


déclarative exécutable gestion des
exceptions

Figure 2 : Capturer des exceptions définies par l'utilisateur

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;

Ce bloc met à jour la description d'un produit. L'utilisateur saisi la nouvelle


description et le numéro du produit. Si l'utilisateur saisie un numéro qui n'existe pas,
aucune ligne ne sera mise à jour dans la table PRODUCT. Une exception est levée
explicitement. Un message s'affiche à l'utilisateur l'informant de l'invalidité du numéro
de produit qu'il a saisi.

6.2.6. La procédure RAISE_APPLICATION_ERROR


La procédure RAISE_APPLICATION_ERROR permet de publier des messages d'erreurs définis par
l'utilisateur depuis un bloc PL/SQL. Ainsi, il est possible d'annoncer des erreurs à une application et
d'éviter de retourner des exceptions non définies.

Syntaxe :

RAISE_APPLICATION_ERROR (error_number, message [,{TRUE|FALSE}]);

error_number est le numéro d'exception spécifié par le développeur qui doit se


trouver entre -20000 et -20999.
message est le message d'erreur associée à l'exception et spécifié par le
développeur. Il s'agit d'une chaîne de caractères avec une taille
maximale de 2048 octets.

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

TRUE | FALSE correspond à un paramètre booléen optionnel. (Si la valeur est


TRUE, l'erreur est placée sur la pile des erreurs précédentes. Si la
valeur est FALSE (valeur par défaut), l'erreur remplace toutes les
erreurs précédentes).

La procédure RAISE_APPLICATION_ERROR peut être utilisée à deux emplacements différents :


- Dans la section exécutable
Exemple :

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

- Dans la section de gestion des exceptions

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.

Une application ne peut appeler la procédure RAISE_APPLICATION_ERROR que depuis un bloc


PL/SQL (nommé ou non) exécutable. Quand elle est appelée, la procédure termine le bloc (ou sous-
programme) et retourne un numéro d'erreur et un message définis par l'utilisateur à l'application. Ce
numéro et ce message peuvent être attrapés comme une erreur du serveur Oracle. L'application obtient
une exception PL/SQL qui peut être traitée en utilisant les fonctions SQLCODE et SQLERRM dans
une routine OTHERS. L'application peut aussi utiliser le pragma EXCEPTION_INIT pour récupérer
les numéros d'erreur retournés par la procédure RAISE_APPLICATION_ERROR.

Exemple :

CREATE PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) AS


curr_sal NUMBER;
BEGIN
SELECT sal INTO curr_sal FROM emp WHERE empno=emp_id;
IF curr_sal IS NULL THEN
RAISE_APPLICATION_ERROR(-20101, 'Salary is missing');
ELSE
UPDATE emp SET sal=curr_sal+amount WHERE empno=emp_id;
END IF;
END raise_salary;

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.

EXEC SQL EXECUTE


DECLARE
...
null_salary EXCEPTION;
PRAGMA EXCEPTION_INIT(null_salary, -20101);
BEGIN
...
raise_salary(:my_emp_id, :my amount);
EXCEPTION
WHEN null_salary THEN
INSERT INTO emp_audit VALUES (:my_emp_id,...);
...
END;
END-EXEC;

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

Note : La procédure RAISE_APPLICATION_ERROR appartient au package DBMS_STANDARD


livré par Oracle. Ce package fournit des "language facilities" pour aider une application à interagir
avec Oracle. Le package DBMS_STANDARD est une extension du package STANDARD, donc il
n'est pas nécessaire de référencer leurs procédures.

6.3.La propagation des exceptions


Quand un sous-bloc traite une exception, le sous-bloc se termine normalement, et le programme
reprend donc dans le bloc "père" immédiatement après l'ordre END du sous-bloc.
Cependant, si le moteur PL/SQL lève une exception qui ne possède pas de routine dans la section de
gestion des exceptions du bloc courant, alors l'exception est propagée successivement dans les blocs
"pères" jusqu'à trouver une routine. Si aucun des blocs ne capture l'exception, une exception non
traitée aboutit dans l'environnement hôte et le programme échoue.

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