Documente Academic
Documente Profesional
Documente Cultură
Jérôme GABILLAUD
Résumé
Ce livre sur Oracle s’adresse à tout informaticien désireux de maîtriser la gestion d’une base de données Oracle.
L’auteur reprend les concepts, définitions et règles du modèle relationnel et détaille son utilisation dans le cadre des outils proposés en standard
avec Oracle Database 11g, c’est-à-dire SQL, SQL*PLUS, PL/SQL et Java.
Les techniques de programmation en PL/SQL sont étudiées afin de pouvoir utiliser toute la puissance du serveur de bases de données Oracle
11g ainsi que les nouveautés apportées par cette version : colonne virtuelle, table en lecture seule, pivot, trigger composé, cache de résultat pour
les fonctions, etc. Par ailleurs, cet ouvrage présente l’outil SQL Developer et l’environnement de développement d’application Web Oracle
Application Express (APEX).
Des exemples nombreux et précis aident le lecteur à maîtriser ces langages de référence dans le monde des bases de données relationnelles.
Ces exemples sont en téléchargement sur cette page.
L'auteur
Ingénieur en Informatique pour l'Industrie, consultant, Jérôme Gabillaud est également responsable pédagogique dans un grand centre de
formation informatique. Spécialiste des systèmes d'accès aux données Microsoft ou Oracle, il est déjà auteur de nombreux ouvrages sur ce
sujet, reconnus pour leurs qualités techniques et pédagogiques.
Ce livre numérique a été conçu et est diffusé dans le respect des droits d’auteur. Toutes les marques citées ont été déposées par leur éditeur respectif. La loi du 11 Mars
1957 n’autorisant aux termes des alinéas 2 et 3 de l’article 41, d’une part, que les “copies ou reproductions strictement réservées à l’usage privé du copiste et non destinées
à une utilisation collective”, et, d’autre part, que les analyses et les courtes citations dans un but d’exemple et d’illustration, “toute représentation ou reproduction intégrale,
ou partielle, faite sans le consentement de l’auteur ou de ses ayants droit ou ayant cause, est illicite” (alinéa 1er de l’article 40). Cette représentation ou reproduction, par
quelque procédé que ce soit, constituerait donc une contrefaçon sanctionnée par les articles 425 et suivants du Code Pénal. Copyright Editions ENI
Ces outils ont un langage commun : le SQL.
Oracle permet de gérer les données d’une application en respectant une logique, devenue standard, le modèle
relationnel. Les fondements de ce modèle ont été établis au début des années 70, par E.F. CODD et restent une
référence pour la gestion des données.
La logique d’extraction des données d’une base conforme au modèle relationnel, constitue l’algèbre relationnelle. Elle
permet aux utilisateurs une approche indépendante du système physique pour arriver à un résultat.
Le SQL est un langage de requêtes descriptif, standard pour toutes les bases de données qui suivent le modèle
relationnel. Ce langage permet toutes les opérations sur les données dans tous les cas d’utilisation de la base.
Avec Oracle, on peut associer au langage SQL un langage procédural, le PL/SQL, qui ajoute de nombreuses possibilités
dans la manipulation des données.
Depuis la version 8i, le SGBD Oracle propose, une nouvelle méthode de gestion des informations dans l’entreprise à
travers l’implémentation du modèle objet relationnel. L’objectif de cette approche est de simplifier la modélisation des
données en permettant le stockage et la manipulation de nouveaux types d’informations. Ces objets métiers, propres
à chaque secteur d’activité ou à chaque entreprise doivent permettre une modélisation plus efficace.
La mise en œ uvre de ce modèle à travers les extensions du langage SQL autorise une migration souple entre le
modèle relationnel pur des versions précédentes et ce nouveau modèle objet relationnel. Le présent ouvrage
s’intéresse à l’approche relationnelle classique.
1. Généralités sur les fichiers
Un fichier informatique est un ensemble d’informations de même nature (texte, code exécutable, données...), portant
un nom et situé sur un support physique (disque dur, disquette, bande, CDRom...).
Un fichier peut avoir différentes fonctions :
● fichier programme : contient du code exécutable par le système d’exploitation.
● fichier texte : contient des caractères ASCII.
● bibliothèque de fonctions : contient du code exécutable pouvant être utilisé par un programme.
● fichier périphérique : permet l’adressage des périphériques (UNIX).
● fichier de données : permet le stockage d’informations d’une application, etc.
Les fichiers de données se distinguent par leur utilité au sein de l’application : le type de fichier. Ce type permettra de
choisir à la fois le support physique du fichier et son organisation.
Types de fichiers de données
Les fichiers permanents contiennent les données de base de l’application. Leurs enregistrements sont,
généralement, composés de nombreuses rubriques et sont de taille importante. La durée de vie de ces
enregistrements est longue. Quelques exemples de fichiers permanents : les fichiers de clients, les catalogues
d’articles, les fiches salariés.
Les fichiers de mouvement contiennent des données se référant aux fichiers permanents, en apportant des
informations supplémentaires, en général ponctuelles. Les enregistrements sont composés principalement des codes
identifiant les enregistrements des fichiers de base. Le nombre d’enregistrements de ces fichiers peut être important
mais leur durée de vie est courte. On peut citer dans ce type, le fichier commandes d’une gestion commerciale qui
stocke la quantité d’articles commandés par un client, ou les fiches de temps d’une gestion de salariés qui stockent le
nombre d’heures travaillées par un salarié sur un poste.
Les fichiers de travail sont créés en général par des applications. Ils contiennent toutes les informations des fichiers
permanents et de mouvement regroupées dans des enregistrements composés. Leur durée de vie est la même que
celle du traitement. Ces fichiers occupent, en général, beaucoup de place. Ce type de fichier comporte, par exemple,
les fichiers d’édition, les résultats de requêtes.
Les fichiers historiques contiennent des données archivées. Elles proviennent, après calcul ou épuration, des fichiers
permanents et des fichiers de mouvement, pour des enregistrements inactifs, ou à mettre en statistique.
2. Organisations classiques de fichiers
L’analyste pourra choisir l’organisation de fichiers à adopter en fonction du type de fichier, du support, de l’application
et, bien sûr, des contraintes du cahier des charges !
Les principaux choix d’organisation de fichiers sont l’organisation séquentielle, le séquentiel indexé, les bases de
données navigationnelles et évidemment les bases de données relationnelles.
Séquentiel
Le principe de cette organisation est de gérer les enregistrements comme des suites d’octets structurées (par des
caractères délimiteurs ou des tailles fixes).
L’avantage réside dans la simplicité d’utilisation, la standardisation des structures et dans l’optimisation de l’espace
de stockage.
Par contre, les fichiers sont indépendants les uns des autres dans l’application et les lectures ne peuvent se faire que
Séquentiel indexé
C’est une amélioration de l’organisation séquentielle, par l’ajout d’un fichier de clés (ou d’index), lié au fichier
séquentiel.
Ce fichier d’index contient des critères de recherche triés (index) et l’adresse de la donnée correspondante dans le
fichier séquentiel.
En plus des avantages du système séquentiel (simplicité, standardisation), on peut donc retrouver rapidement un
enregistrement en fonction de la clé.
Le principal inconvénient reste l’indépendance des fichiers dans l’application, d’où la nécessité de beaucoup de
programmation pour gérer l’intégrité des données. On peut également noter un gaspillage de place dû à la
redondance des données (notamment les clés).
Bases navigationnelles
Ce sont des collections de fichiers, logiquement appareillés entre eux. Ces bases ont été créées sur des systèmes
propriétaires afin de compenser la faiblesse des organisations précédentes, en ce qui concerne la traduction du
dictionnaire des données de l’analyse.
Les avantages de ces bases sont nombreux, notamment la sécurité d’accès avec connexion d’utilisateurs à la base
protégée par mot de passe ; le respect, au niveau des structures même, de l’intégrité de données ; de nouvelles
possibilités de lecture de données grâce à des liens directs entre enregistrements de fichiers différents (lectures
chaînées).
De gros inconvénients découlent de ces systèmes. Parmi ceuxci on peut citer la complexité de maintenance et
d’utilisation, la "gourmandise" en espace disque, mémoire et CPU, et enfin la spécificité de ces bases par rapport au
système d’exploitation.
1. Concepts et définitions
Le modèle relationnel repose sur des concepts de base simples (domaine, relation, attribut), auxquels s’appliquent
des règles précises.
La mise en œ uvre de la base est facilitée par un langage assertionnel (non procédural) simple, basé sur une logique
ensembliste.
a. Domaine
C’est un ensemble de valeurs caractérisées par un nom.
Cardinal
C’est le nombre d’éléments d’un domaine.
Exemple
Le dictionnaire des données de l’analyse d’une gestion commerciale peut comporter, entre autres, des spécifications sur la
gestion des états de commande ou des numéros d’ordre à afficher. Le modèle relationnel les traduira de la manière
suivante :
b. Produit cartésien
Le produit cartésien P entre plusieurs domaines D1, D2,..., Dn noté P = D1 X D2 X ... X Dn est l’ensemble des nuplets
(tuples) (d1, d2, ..., dn) où chaque di est un élément du domaine Di.
Exemple
Si on veut gérer deux domaines (codes et taux), on pourra obtenir des doublets composés d’un code et d’un taux.
Codes = {1,2,3,4}
Taux de TVA = {0,5.5,19.6}
Codes X Taux de TVA ={(1,0),(1,5.5),(1,19.6),
(2,0),(2,5.5),(2,19.6),(3,0),(3,5.5),(3,19.6),
(4,0),(4,5.5),(4,19.6)}
c. Relation
Une relation définie sur les domaines D1, D2,... , Dn est un sousensemble du produit cartésien de ces domaines
caractérisé par un nom.
Attribut
C’est une colonne d’une relation caractérisée par un nom.
Degré
C’est le nombre d’attributs d’une relation.
Représentation
Elle se fait sous forme de tableau (table), en extension :
ou en compréhension :
2. Principales règles
Le modèle relationnel gère donc un objet principal, la relation, associée aux concepts de domaine et d’attribut.
Des règles s’appliquent à cette relation afin de respecter les contraintes liées à l’analyse.
Quelquesunes de ces règles sont :
Cohérence
Toute valeur prise par un attribut doit appartenir au domaine sur lequel il est défini.
Unicité
Tous les éléments d’une relation doivent être distincts.
Identifiant
Attribut ou ensemble d’attributs permettant de caractériser de manière unique chaque élément de la relation.
Clé primaire
Identifiant minimum d’une relation.
Clés secondaires
Autres identifiants de la relation.
Intégrité référentielle
Cette règle impose qu’un attribut ou ensemble d’attributs d’une relation apparaisse comme clé primaire dans une
autre relation.
Clé étrangère
Attribut ou ensemble d’attributs vérifiant la règle d’intégrité référentielle.
Exemple
L’analyse d’une gestion commerciale nous impose de gérer des clients ayant des caractéristiques (Nom, adresse) et des
commandes que passent ces clients.
On pourra proposer le modèle suivant :
CLIENTS (NUMEROCLI,NOMCLI,ADRESSECLI)
NUMEROCLI identifiant clé primaire de CLIENTS
(NOMCLI,ADRESSECLI) identifiant clé secondaire de CLIENTS
COMMANDES (NUMEROCDE,DATECDE,NUMEROCLI,ETATCDE)
NUMEROCDE identifiant clé primaire de COMMANDES
NUMEROCLI clé étrangère de COMMANDES, référençant NUMEROCLI de CLIENTS
Valeur nulle
Dans le modèle relationnel, la notion de nullité est admise. C’est une valeur représentant une information inconnue ou
inapplicable dans une colonne.
Elle est notée _ , ^ ou NULL.
Contrainte d’entité
Toute valeur participant à une clé primaire doit être non NULL.
Exemple
Dans la relation article, on admet que le prix ou le code TVA peuvent être inconnus, mais la référence de l’article (clé
primaire) doit être renseignée.
1. Opérateurs
a. Union
L’union entre deux relations de même structure (degré et domaines) donne une table résultante de même structure
ayant comme éléments l’ensemble des éléments distincts des deux relations initiales.
Notation : Rx = R1 ∪ R2
Exemples
Soient les tables CLIOUEST et CLICENTRE :
Clients des deux régions :
∪ CLICENTRE
CLIENTS=CLIOUEST ∪
b. Intersection
L’intersection entre deux relations de même structure (degré et domaines) donne une table résultante de même
structure ayant comme éléments l’ensemble des éléments communs aux deux relations initiales.
Notation : Rx = R1 ∩ R2
Exemple
Clients communs aux deux régions :
CLICOMMUN=CLIOUEST ∩ CLICENTRE
c. Différence
Exemple
Clients gérés uniquement par la région OUEST :
CLIOUESTSEUL=CLIOUEST - CLICENTRE
d. Restriction
La restriction selon une condition produit, à partir d’une relation, une relation de même schéma n’ayant que les
éléments de la relation initiale qui répondent à la condition.
Notation : Rx = σ (condition) R1
La condition s’exprime sous la forme :
opérateur
un opérateur de comparaison : =, <>, >, <, >=, <=
valeur
une constante ou un autre attribut.
Exemples
Clients de NANTES :
CLI44=σ(ADRESSE="NANTES")CLIOUEST
Articles de la famille AB :
ART1=σ(REFART>="AB" ET REFART<"AC")ARTICLES
Tapis "pas chers" :
ART2=σ(PRIX<=1000)ART1
e. Projection
Exemples
Commandes et états de commande :
CDE= π COMMANDES(NUMEROCDE,NUMEROCLI,ETATCDE)
Clients ayant des commandes :
CLICDE1= π COMMANDES(NUMEROCLI)
Clients et états de commande :
CLIDE2= π COMMANDES(NUMEROCLI,ETATCDE)
f. Produit cartésien
Le produit cartésien entre deux relations produit une relation ayant comme schéma tous les attributs des deux
relations existantes et comme éléments l’association de chaque ligne de la première table avec chaque ligne de la
deuxième.
Notation : Rx = S1 X S2
Exemple
Soient les tables :
g. Jointures
La jointure entre deux relations selon une condition est produite par la restriction sur le produit cartésien.
Notation : Rx = S1 JOIN (condition) S2
Exemple
Soient les tables :
Thetajointure
La condition est une comparaison entre deux attributs.
Equijointure
La condition porte sur l’égalité entre deux attributs.
Jointure naturelle
Équijointure entre les attributs portant le même nom.
h. Calculs élémentaires
Projection sur une relation associée à un calcul portant sur chaque ligne pour créer un ou plusieurs nouveaux
attributs.
Notation : Rx = π S (A1,...,N1 = expression calculée...)
L’expression calculée peut être :
● une opération arithmétique,
● une fonction portant sur une chaîne.
Exemple
On veut obtenir le montant d’une ligne de commande (Prix * Quantité).
LIGCDEVALO = π LIGCDE(NOCDE,NOLIG,REFART,
VALOLIG=QTECDE*PRIXHT)
i. Calcul d’agrégats
Projection sur une relation associée à un ou des calculs statistiques portant sur un attribut pour tous les éléments
de la relation ou du regroupement lié à la projection afin de créer un ou plusieurs nouveaux attributs.
Notation : Rx = π S (A1,...,N1= fonction statistique (Ax),...)
Les fonctions statistiques sont :
COUNT (*)
nombre de lignes.
COUNT (attribut)
nombre de valeurs non nulles.
SUM (attribut)
somme des valeurs non nulles.
AVG (attribut)
moyenne des valeurs non nulles.
MAX (attribut)
valeur maximum (non nulle).
MIN (attribut)
valeur minimum (non nulle).
Exemples
Nombre total de clients dans la table.
NBCLI=π CLIENTS(N=COUNT(*))
Total des montants de la ligne par commande :
Prix les plus élevés, les moins élevés et moyenne des prix par catégorie d’articles :
STATART=π ARTICLES(CATEGORIE,PLUSCHER=MAX(PRIX),
MOINSCHER=MIN(PRIX),MOYENNE=AVG(PRIX))
2. Étapes de résolution d’un problème
À partir d’une base de données connue (schémas, domaines, relations, éléments), la résolution d’un problème se fait
en trois étapes.
a. Analyser le besoin
● Transcrire sous forme de relation résultante des besoins exprimés par le prescripteur.
● Déterminer les attributs et les relations à utiliser.
● Exprimer les calculs élémentaires et d’agrégats pour créer les attributs inexistants.
b. Établir la "vue"
La vue est une relation intermédiaire contenant tous les attributs permettant de réaliser l’extraction, avec leurs
relations d’origine, leurs classes d’utilité, et les opérations à appliquer.
Classes d’attribut
Classe a : attribut participant à la relation résultante.
Classe b : attribut participant à un calcul.
Classe c : attribut participant à une restriction.
Classe d : attribut participant à une jointure.
c. Ordonnancer et exprimer les opérations
D’une façon générale, et sauf exception, l’ordonnancement des opérations peut s’exprimer de la façon suivante :
Relations concernées.
Restrictions (pour éliminer les lignes inutiles).
Jointures, Produits cartésiens, Unions, Intersections, Différences (pour associer les lignes restantes).
Calculs élémentaires (pour créer les nouvelles colonnes).
Calculs d’agrégats (pour les colonnes statistiques).
Répéter les étapes du pour les autres regroupements.
Restrictions par rapport aux attributs calculés.
Projection finale pour éliminer les attributs inutiles dans la table résultante.
Exemple
Soit la base de données composée des tables suivantes :
CLIENTS (NOCLI,NOMCLI,ADRESSE)
ARTICLES (REFART,DESIGNATION,PRIXHT)
COMMANDES (NOCDE,NOCLI,DATECDE,ETATCDE)
LIGNESCDE (NOCDE,NOLIG,REFART,QTECDE)
On veut obtenir l’édition de la confirmation de la commande N°1301.
Maquette du document :
À l’analyse de la maquette et des tables initiales, on déduit que :
Pour établir le document, il faudrait donc la table suivante :
CONFCDE (NOCDE,DATECDE,NOMCLI,ADRESSE,REFART,
DESIGNATION,PRIXHT,QTECDE,MTHT,TOTHT)
avec MTHT = PRIXHT*QTECDE par ligne de commande et TOTHT = SUM(MTHT) pour la commande.
Vue
Opérations
Restriction sur le numéro de commande :
T1=σ(NOCDE=1301) COMMANDES
T2=σ(NOCDE=1301) LIGNESCDE
Jointure naturelle COMMANDES et LIGNESCDE :
Jointure naturelle COMMANDES et CLIENTS :
Jointure naturelle LIGNESCDE et ARTICLES :
T5=T4 JOIN (T4.REFART=ARTICLES.REFART) ARTICLES
Projection de calcul élémentaire de MTHT et élimination des colonnes inutiles :
T6=πT5(NOCDE,DATCDE,NOMCLI,ADRESSE,REFART,
DESIGNATION,PRIXHT,QTECDE,MTHT=PRIXHT*QTECDE)
Projection de calcul d’agrégat pour TOTHT :
T7=πT6(NOCDE,TOTHT=SUM(MTHT))
Jointure à effectuer pour avoir toutes les colonnes dans la table résultante :
L’intérêt du SQL réside dans les caractéristiques suivantes :
Normalisation
Il implémente le modèle relationnel, et les principaux organismes de normalisation le décrivent :
● l’ANSI (American National Standards Institute) dans les documents ANSI 90751:1999, ANSI 90752:1999 et ANSI
90755:1999. Il est possible d’obtenir plus de détails sur les documents qui définissent la norme en se rendant
sur le site Web de l’ANSI (http://webstore.ansi.org) ou sur le site Web de NCITS (National Comittee for
Information Technology Standards) qui reprend une partie des standards ANSI dont le SQL
(http://www.ncits.org).
● l’ISO (International Organisation for Standardization) dans les documents ISO/IEC 90751:1999, ISO/IEC 9075
2:1999 et ISO/IEC 90755:1999. Il est possible d’obtenir une copie des documents de normalisation sur le site
Web de l’ISO : http://www.iso.ch/iso/iso_catalogue.htm.
Standard
Du fait de cette normalisation, la plupart des éditeurs de SGBDR intègrent le SQL à leurs produits (INFORMIX, DB2, MS
SQL Server, SYBASE...).
Les données, requêtes et applications sont donc assez facilement portables d’une base à une autre.
Non Procédural
Le SQL est un langage de requête qui permet à l’utilisateur de demander un résultat sans se préoccuper des moyens
techniques pour trouver ce résultat. Un composant du moteur de la base (l’optimiseur) se charge de cette tâche.
Les instructions sont écrites dans un langage courant (l’anglais !).
Le SQL manipule aussi bien des ensembles d’enregistrements qu’un seul enregistrement, et permet l’utilisation du
résultat dans une autre commande. On n’a donc pas besoin de structures de contrôle comme dans les langages de
programmation courants (langages de 3ème génération).
Universel
Le SQL peut être utilisé à tous les niveaux dans la gestion d’une base de données :
● administration système,
● administration de la base,
● développement et application,
● gestion de données simple.
Tous les utilisateurs de la base ont donc un langage commun.
Ce langage permet d’autre part d’effectuer toutes les opérations :
● interrogation des données,
● ajout, suppression, modification de données,
● gestion des objets (structures),
● gestion de la sécurité d’accès aux données.
Une base de données relationnelle est composée d’entités logiques ou physiques manipulables par le langage SQL.
Ces entités sont appelées objets SQL.
Le premier est la base de données qui regroupe l’ensemble des autres objets.
On peut regrouper ces objets en différentes catégories en fonction de leur utilité.
a. La gestion des données
table
Ensemble de lignes (row) et de colonnes (column).
index
Colonne ou ensemble de colonnes permettant l’accélération des recherches.
view
Requête pouvant être manipulée comme une table (table virtuelle).
synonym
Nom alternatif pour une table ou une view.
sequence
Générateur de série de nombres.
snapshots
Table contenant le résultat d’une requête faite sur une table gérée dans une base distante.
database links
Lien avec des bases distantes.
b. Le stockage physique
cluster
Regroupement physique de tables ayant des colonnes communes.
tablespace
Regroupement logique de fichiers.
directory
Représentation dans la base de données d’un répertoire du système d’exploitation hôte.
c. Le stockage d’instructions
schema
Ensemble des objets de la base logique appartenant à un même utilisateur.
procedure
function
Ensemble de code procédural nommé retournant une valeur.
database trigger
Ensemble de code procédural associé à une table.
packages
Collection d’objets (procédure, fonction...) stockés ensemble.
library
Représentation d’une collection de procédures externes à Oracle, stockées dans des bibliothèques partagées du
système hôte.
d. La gestion des utilisateurs
profile
Ensemble nommé de limites système.
role
Ensemble de privilèges pouvant être attribués à des utilisateurs.
user
Utilisateur pouvant se connecter et accéder aux ressources de la base.
Les objets créés par les utilisateurs du SGBDR Oracle doivent être nommés.
e. Dénomination des objets
Elle doit respecter les règles suivantes :
● 1 à 30 caractères, sauf database (8) et database links (128).
● Pas de distinction majusculeminuscule.
● Commencent par une lettre.
● Caractères alphanumériques plus _ $ et # (plus @ et . pour les database links).
● Ne doit pas être un mot réservé.
● Doit être unique, à l’intérieur du SCHEMA d’un utilisateur, même pour des types d’objets différents.
Conventions
Les noms utilisés doivent être significatifs, sans être trop longs.
Il est recommandé d’utiliser des noms identiques pour désigner les mêmes entités dans des objets différents de la
base de données (nom de colonne).
Si les noms d’objets sont donnés sans guillemets, Oracle ne tient pas compte de la casse utilisée (les noms sont
stockés en majuscules à la création des objets et lors des références ultérieures, Oracle opère automatiquement
une conversion en majuscules).
2. Catégories d’instructions
Les instructions SQL sont regroupées en catégories en fonction de leur utilité et des entités manipulées.
a. DDL (Data Definition Language)
Il permet de gérer les "structures" des objets :
● Créer, modifier, supprimer des objets.
● Autoriser ou interdire l’accès aux données.
● Activer, désactiver l’audit.
● Commenter le dictionnaire des données.
Les instructions du DDL sont : CREATE, ALTER, DROP, GRANT, REVOKE, AUDIT, NOAUDIT, ANALYZE, RENAME,
TRUNCATE, COMMENT, FLASHBACK, PURGE.
b. DML (Data Manipulation Language)
Il permet la gestion des données des objets existants :
● Ajout, suppression, modification des lignes.
● Visualisation du contenu des tables.
● Verrouillage des tables.
Les instructions du DML sont : INSERT, UPDATE, DELETE, SELECT, EXPLAIN PLAN, LOCK TABLE, MERGE.
c. Transaction Control language
Il gère les modifications faites par le DML :
● Caractéristiques des transactions.
● Validation, annulation des modifications.
Les instructions du Transaction Control sont : COMMIT, SAVEPOINT, ROLLBACK, SET TRANSACTION, SET CONSTRAINT.
d. Session Control language
Il permet la gestion d’une session utilisateur :
● Modification des caractéristiques de session.
● Activation, désactivation des privilèges utilisateurs.
Les instructions du Session Control sont : ALTER SESSION, SET ROLE.
Il permet d’intégrer le DDL, le DML et le Transaction Control à un langage de programmation :
● Déclarations d’objets ou d’instructions.
● Exécutions d’instructions.
● Gestions des variables et des cursors.
● Traitement des erreurs.
Les instructions du Embedded SQL sont : DECLARE, TYPE, DESCRIBE, VAR, CONNECT, PREPARE, EXECUTE, OPEN,
FETCH, CLOSE, WHENEVER.
1. Les types de données
CHAR (n)
Chaîne de caractères de longueur fixe : n octets complétés à droite par des espaces (n <= 2000).
VARCHAR2 (n)
Chaîne de caractères de longueur variable : n octets au maximum (n <=4000)
NCHAR (n)
Chaîne de caractères de longueur fixe : n octets complétés à droite par des espaces (n <=2000). Les caractères sont
codés suivant le jeu de caractères national actif.
NVARCHAR2 (n)
Chaîne de caractères de longueur variable : n octets au maximum (n <=4000). Les caractères sont codés suivant le
jeu de caractères national actif.
NUMBER (p,s)
Numérique avec une précision de p chiffres dont s décimales avec (1 <= p <= 38 et 84 <= s <= +127)
DATE
Date comprise entre 1er janvier 4712 avant JC et le 31 décembre 9999 après JC.
TIMESTAMP (p)
Données de type Date (Année, mois, jour, heure, minute et seconde) dans laquelle il est possible de préciser, à l’aide
de la précision p, le nombre de chiffres significatifs pour les fractions de secondes. Par défaut ce nombre est 6.
TIMESTAMP(p) WITH TIME ZONE
Données de type TIMESTAMP avec le décalage horaire.
TIMESTAMP(p) WITH LOCAL TIME ZONE
Données de type TIMESTAMP WITH TIME ZONE qui sont stockées sur le serveur en tenant compte de la plage horaire
du serveur, mais ces données sont affichées sur le poste client en tenant compte de la zone horaire définie au niveau
de la session.
BLOB
Données binaires non structurées (jusqu’à 128 To selon la taille de bloc utilisé dans la base).
CLOB
Chaîne de caractères de longueur variable (jusqu’à 128 To selon la taille de bloc utilisé dans la base). Ne peut contenir
que des caractères codés sur 1 octet.
NCLOB
Chaîne de caractères de longueur variable (jusqu’à 128 To selon la taille de bloc utilisé dans la base). Prend en charge
BFILE
Données binaires stockées dans des fichiers extérieurs à la base de données (jusqu’à 2 64 1 octets, sauf limitation du
système d’exploitation).
Types assurant la compatibilité avec les versions antérieures :
LONG
Chaîne de caractères à longueur variable (2 Go au maximum).
RAW (n)
Données binaires de longueur variable (n octets maximum ; n<=2000) ; contenu non interprété par Oracle.
LONG RAW (n)
Données binaires de longueur variable (4 Go maximum) ; contenu non interprété par Oracle.
2. Création d’une table
Une table est un ensemble de lignes et de colonnes. La création consiste à définir (en fonction de l’analyse) le nom de
ces colonnes, leur format d’utilisation (type), une valeur par défaut à la création de la ligne (DEFAULT), les règles de
gestion s’appliquant à la colonne (CONSTRAINT). Si une règle de gestion concerne plusieurs colonnes de la ligne, on
définit une contrainte de table. Il est possible de définir jusqu’à 1000 colonnes pour chaque table.
Syntaxe
a. Contraintes de colonne
NULL/NOT NULL
Autorise (NULL) ou interdit (NOT NULL) l’insertion de valeur NULL pour cet attribut.
PRIMARY KEY
Désigne l’attribut comme clé primaire de la table. Cette contrainte ne peut apparaître qu’une seule fois dans
l’instruction.
UNIQUE
Désigne l’attribut comme clé secondaire de la table. Dans le cas de contrainte UNIQUE portant sur une seule colonne,
l’attribut peut prendre la valeur NULL. Cette contrainte peut apparaître plusieurs fois dans l’instruction.
REFERENCES table [(colonne)] [ON DELETE {CASCADE | SET NULL}]
Contrainte d’intégrité référentielle pour l’attribut dans la table détail en cours de définition. Les valeurs prises par cet
attribut doivent exister dans l’attribut colonne qui possède une contrainte PRIMARY KEY ou UNIQUE dans la table
maître.
CHECK (condition)
Vérifie lors de l’insertion de lignes que l’attribut réalise la condition (pour la syntaxe de la condition, voir Manipulation
des données).
Attention, il n’est pas possible dans une contrainte CHECK de faire référence à la fonction SYSDATE ou bien
CURRENT_DATE pour comparer la valeur d’une colonne de type date avec le résultat de l’exécution de cette fonction.
Il est par contre tout à fait possible, si on le souhaite, de comparer à l’aide d’une contrainte CHECK, les valeurs de 2
b. Contraintes de table (portant sur plusieurs colonnes)
PRIMARY KEY (colonne,...)
Désigne la concaténation des attributs cités comme clé primaire de la table. Cette contrainte ne peut apparaître
qu’une seule fois dans l’instruction.
UNIQUE (colonne,...)
Désigne la concaténation des attributs cités comme clé secondaire de la table. Dans ce cas de contrainte UNIQUE
portant sur des colonnes concaténées, au moins une des colonnes participant à cette clé secondaire doit permettre
de distinguer la ligne. Cette contrainte peut apparaître plusieurs fois dans l’instruction.
FOREIGN KEY (colonne, ...) REFERENCES table [(colonne, ...)] [ON DELETE {CASCADE | SET NULL}]
Contrainte d’intégrité référentielle pour l’ensemble des attributs dans la table détail en cours de définition. Les
valeurs prises par ces attributs doivent exister dans l’attribut colonne qui possède une contrainte PRIMARY KEY ou
UNIQUE dans la table maître table.
CHECK (condition)
Cette contrainte permet d’exprimer une condition qui doit exister entre plusieurs attributs de la ligne (pour la
syntaxe de la condition, voir Manipulation des données).
Les contraintes de tables portent sur plusieurs colonnes de la table sur laquelle elles sont définies. Il n’est
pas possible de définir une contrainte d’intégrité utilisant des colonnes provenant de deux ou plusieurs
tables. Ce type de contrainte sera mis en œ uvre par l’intermédiaire de déclencheurs de base de données (triggers)
dont la définition est abordée plus loin dans cet ouvrage.
c. Complément sur les contraintes
ON DELETE CASCADE
Demande la suppression des lignes dépendantes dans la table en cours de définition, si la ligne contenant la clé
correspondante dans la table maître est supprimée. Si cette option n’est pas indiquée, la suppression sera
impossible dans la table maître s’il existe des lignes référençant cette valeur de clé.
ON DELETE SET NULL
Demande la mise à NULL des colonnes constituant la clé étrangère qui font référence à la ligne supprimée. Si cette
option n’est pas indiquée, la suppression sera impossible dans la table maître s’il existe des lignes référençant cette
valeur de clé.
[NOT] DEFERRABLE
Repousse ou non (NOT) la vérification de la contrainte au moment de la validation de la transaction.
d. Dénomination des contraintes
Les contraintes peuvent être nommées afin d’être plus facilement manipulées ultérieurement (activation,
suppression). Dans le cas où aucun nom n’est affecté explicitement à une contrainte, Oracle génère
automatiquement un nom de la forme SYS_Cn (n est un nombre entier unique).
Lors de l’affectation explicite d’un nom à une contrainte, il est pratique d’utiliser la convention de dénomination
suivante :
Table_Colonne_TypeDeContrainte
nom de la table sur laquelle est définie la contrainte
Colonne
nom de la ou des colonne(s) sur laquelle (lesquelles) est (sont) définie(s) la contrainte.
TypeDeContrainte : mnémonique associé au type de contrainte :
PK Clé primaire
UQ Unique
NN Not Null
CK Check
RF Références
FK Clé étrangère.
Exemples
Création d’une table ARTICLES avec comme seule contrainte la clé primaire REFART :
Table créée.
SQL>
Dans ce cas, DESIGNATION, PRIX et QTESTK peuvent être NULL : PRIX et QTESTK peuvent être négatifs !
Création d’une table CLIENTS avec traduction des contraintes sur les colonnes :
Table créée.
SQL>
Le NOCLI et le NOMCLI sont obligatoires ;
Le NOCLI doit être strictement positif ;
Le CODE_POSTAL doit être dans l’intervalle indiqué.
Création de la table des commandes en utilisant une syntaxe de type contrainte de table pour définir les contraintes
d’intégrité.
Table créée.
SQL>
Création d’une table LIGCDES avec des contraintes de référence sur des colonnes et une contrainte de table pour la clé
primaire.
Table créée.
SQL>
Quel que soit le mode de définition des contraintes (niveau colonne ou niveau table), le résultat est le
même. Seules les contraintes d’intégrité portant sur plusieurs colonnes de la même table doivent être
définies en utilisant une syntaxe contrainte de table.
e. Colonne virtuelle
Une colonne virtuelle est une colonne définie par une expression qui est évaluée lors de chaque interrogation ;
aucune valeur n’est stockée dans la table pour la colonne en question. Cette fonctionnalité est apparue en version
11.
Syntaxe
Le type de données est optionnel ; s’il n’est pas spécifié, Oracle le détermine à partir du type de données de
l’expression.
La clause AS permet de spécifier l’expression qui détermine la valeur de la colonne. Cette expression peut référencer
d’autres colonnes réelles (non virtuelles) de la même table mais aucune colonne d’une autre table.
Les motsclés GENERATED ALWAYS et VIRTUAL sont optionnels ; ils peuvent être spécifiés pour rendre la syntaxe
plus claire.
Une contrainte de colonne peut être définie sur une colonne virtuelle.
Exemple
Table créée.
SQL>
SQL> insert into ARTICLES (REFART,DESIGNATION,PRIXHT,TAUXTVA)
2 values (’XT10’,’Lot de 10 crayons’,10,19.6);
1 ligne créée.
1 ligne créée.
SQL>
SQL> select DESIGNATION,PRIXHT,PRIXTTC from ARTICLES;
3. Suppression d’une table
Supprimer une table revient à éliminer sa structure et toutes les données qu’elle contient ; les index associés sont
également supprimés ; les vues construites directement ou indirectement sur cette table sont invalidées
automatiquement par Oracle.
Si la clé primaire de la table est référencée dans d’autres tables par des contraintes REFERENCES ou FOREIGN KEY, la
clause CASCADE CONSTRAINTS permet de supprimer ces contraintes d’intégrité référentielle dans les tables "enfants".
La clause PURGE permet de supprimer la table et de libérer l’espace physique occupée par cette table. En l’absence de
cette clause, la table est supprimée logiquement mais pas physiquement. Il est alors possible d’utiliser l’instruction
FLASHBACK TABLE pour retrouver la table et ses données au moment de la suppression.
Avec ce principe de fonctionnement, Oracle permet de ne plus rendre définitif une action de suppression de table et
facilite ainsi la restauration des tables supprimées par erreur.
Syntaxe
Exemples
Suppression d’une table CLIENTS dont la colonne NOCLI est clé étrangère dans la table COMMANDES :
Table supprimée.
Suppression de la table des clients avec demande de libération de l’espace physique.
Il est possible de modifier la structure d’une table à plusieurs niveaux :
● ajout de colonnes (nom, type, valeur par défaut, contrainte NOT NULL),
● ajout de contraintes de colonne (contrainte NOT NULL uniquement),
● ajout de contraintes de table,
● redéfinition d’une colonne (type, valeur par défaut),
● activation, désactivation de contraintes de colonne ou de table,
● suppression de contraintes de colonne ou de table,
● changement du nom de la table.
● autorisation ou non de modifications dans la table.
a. Ajout ou modification de colonnes
Syntaxe
Exemple
Table modifiée.
SQL> alter table CLIENTS modify (ADRCLI char(30));
Table modifiée.
SQL> describe CLIENTS
Name Null? Type
------------------------------ --------- ------------
NOCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
ADRCLI CHAR(30)
CODE_POSTAL NUMBER(5)
VILLE CHAR(30)
TEL CHAR(14)
SQL>
b. Ajout d’une contrainte de table
Syntaxe
La syntaxe de déclaration de contrainte est identique à celle vue lors de la création de la table.
L’exemple suivant permet d’ajouter une contrainte de validation à la table ARTICLES.
Table modifiée.
SQL>
Il est également possible de définir une contrainte de non nullité par l’intermédiaire de la commande ALTER
TABLE.
Si des données sont déjà présentes dans la table au moment où la contrainte d’intégrité est ajoutée, alors toutes
les lignes d’information doivent vérifier la contrainte. Dans le cas contraire, la contrainte n’est pas posée sur la table.
La clause EXCEPTION INTO TABLE nom_table permet de connaître le rowid (l’identifiant de la ligne pour Oracle) des
lignes qui violent la contrainte d’intégrité que l’on tente de poser ou de réactiver. Il est ainsi possible de résoudre
facilement le problème.
La table qui va recevoir les références des lignes qui empêchent la création de la contrainte d’intégrité peut être
créée par l’intermédiaire du script utlexcpt.sql (utilisation du rowid physique) ou utlexpt1.sql (utilisation du rowid
universel) situé dans le répertoire ORACLE_HOME\rdbms\admin.
Création de la table des exceptions :
Positionnez les références des lignes posant problème dans la table des exceptions.
Tentative d’ajout d’une contrainte d’unicité sur l’adresse des clients :
Il faut maintenant utiliser les rowids pour connaître les lignes qui empêchent l’ajout de la contrainte.
Liste des numéros clients qui possèdent la même adresse :
Structure d’un script de création de table
c. Suppression d’une contrainte
Syntaxe
Exemple
Table modifiée.
SQL>
d. Activation, désactivation d’une contrainte
La commande ALTER TABLE permet également d’activer et de désactiver les contraintes d’intégrité. Cette opération
peut être intéressante lors d’un import massif de données afin, par exemple, de limiter le temps nécessaire à cette
importation.
Syntaxe
ENABLE VALIDATE
Active la contrainte si l’ensemble des lignes déjà présentes dans la table la respecte.
ENABLE NOVALIDATE
Active la contrainte pour les manipulations de données suivantes (ne vérifie pas les données actuelles).
DISABLE
Désactive la contrainte.
Exemple
Désactivation de la contrainte sur la colonne CODE_POSTAL de la table CLIENTS. Insertion dans cette table d’une valeur
incompatible avec la contrainte désactivée. Tentative de réactivation de la contrainte avec vérification par rapport aux
données présentes dans la table.
Table modifiée.
ERREUR à la ligne 1:
ORA-02293: impossible ajouter contrainte de vérification
[CLIENTS_CODE_POSTAL_CK] - valeurs non conf. trouvées
SQL>
e. Modification d’une contrainte
Il n’est pas possible de modifier la définition d’une contrainte. Par contre, il est tout à fait possible de modifier l’état
d’une contrainte.
Syntaxe
Les états possibles pour la contrainte sont :
DEFERRABLE
La validation de la contrainte peut être reportée à la fin de la transaction.
NOT DEFERRABLE
La contrainte est vérifiée à la fin de chaque instruction du DML. Cette option est activée par défaut.
INITIALLY IMMEDIATE
Pour chaque nouvelle transaction, le fonctionnement par défaut consiste à vérifier la contrainte à la fin de chaque
ordre du DML. Cette option est sélectionnée par défaut.
INITIALLY DEFERRED
Implique que la contrainte est en mode DEFERRABLE et précise que par défaut cette contrainte est vérifiée
uniquement à la fin de la transaction.
RELY ou NORELY
La valeur RELY permet d’indiquer qu’une contrainte dans le mode NOVALIDATE peut être prise en compte par Oracle
pour la réécriture de requête (query rewrite). La valeur par défaut est NORELY.
USING INDEX
Exemple
Modification de la contrainte de référence entre les tables LIGNESCDE et COMMANDES.
f. Suppression de colonnes
Il est possible de supprimer une colonne en utilisant la clause DROP COLUMN de l’instruction ALTER TABLE. Cette
opération permet de récupérer l’espace disque occupé par chaque colonne supprimée.
Syntaxe
ou
Exemple
Suppression de la colonne TEL dans la table CLIENTS.
Une suppression de colonne dans une table existante et possédant de nombreuses lignes peut s’avérer une
opération très longue. Il peut parfois être plus opportun de rendre la colonne inutilisable à l’aide de la clause SET
UNUSED. Cette option ne permet pas de libérer l’espace disque occupé par la colonne, mais elle permet de planifier
l’opération de suppression de la colonne à un moment où la charge de travail pour le serveur est moindre.
Syntaxe
Exemple
Rendre inutilisable la colonne TEL de la table CLIENT. Dans un premier temps, la colonne est masquée comme inutilisée.
Dans un deuxième temps, il faut supprimer toutes les colonnes inutilisées de la table CLIENT. Lors de cette
opération, on demande au système de réaliser un point de synchronisation (CHECKPOINT) toutes les 200
suppressions. Cette précaution évite de saturer le cachebuffer de données avec les données en cours de
suppression et permet de réaliser très souvent des écritures disque.
Pour connaître les tables qui contiennent des colonnes inutilisées, il faut interroger la vue du dictionnaire de données
intitulée DBA_UNUSED_COL_TABS.
g. Changement de nom d’une table
L’instruction RENAME permet de renommer une table mais également les vues, les séquences et les synonymes
privés.
Les synonymes publics ne peuvent être renommés et doivent être supprimés puis recréés.
Syntaxe
Exemple
Renommer la table ARTICLES en table PRODUITS.
h. Mettre une table en lecture seule ou en lecture écriture
Depuis la version 11, il est possible de mettre une table en lecture seule pour interdire toute modification de
données dans la table, puis de la remettre en lecture écriture ultérieurement.
Syntaxe
Exemple
Table modifiée.
Table modifiée.
2 ligne(s) supprimée(s).
La structure d’une table en lecture seule ne peut pas être modifiée (ajout, modification, suppression de
colonne). Par contre, une table en lecture seule peut être supprimée (DROP TABLE) !
5. Restauration d’une table
L’instruction FLASHBACK TABLE permet de restaurer de façon automatique une table modifiée de façon accidentelle. Le
laps de temps pendant lequel il est possible de revenir à la version précédente de la table est fonction de l’espace
d’annulation réservé par la base.
Il n’est pas possible d’inclure cette opération dans une transaction.
Oracle ne peut pas exécuter l’instruction FLASHBACK TABLE si une modification de structure a eu lieu sur la table.
Cette instruction permet d’annuler la suppression d’une table effectuée avec l’instruction DROP TABLE.
Syntaxe
Exemple
Dans l’exemple suivant, la table ligcdes est supprimée par mégarde et restaurée grâce à l’action de l’instruction FLASHBACK
TABLE.
L’instruction FLASHBACK TABLE permet d’annuler les modifications effectuées par les instructions INSERT, UPDATE ou
DELETE sur une table. Il est même possible de restaurer les données d’une ou de plusieurs tables jusqu’à une date et
heure précises.
Pour pouvoir bénéficier de cette fonctionnalité, la table doit être configurée de façon à prendre en charge les
mouvements de lignes dans la table. Il est possible de lever cette option soit lors de la création de la table, en
utilisant la clause enable row movement, ou bien lors d’une modification de la table.
Syntaxe
Exemple
Activer la prise en charge des mouvements de lignes sur la table des clients.
Dans l’exemple suivant, les clients dont le nom commencent par E ont été supprimés par mégarde. La transaction est
maintenant validée et les données modifiées sont visibles de tous les utilisateurs.
Heureusement, l’utilisateur a noté l’heure à laquelle cette opération malencontreuse a été exécutée. Il est alors possible de
restaurer les données supprimées sans pour autant faire une restauration complète de la base de données.
Il existe également au niveau de la base de données l’instruction FLASHBACK DATABASE.
6. Gestion des index
Les index ont pour but l’amélioration des performances des requêtes. Ils sont utilisés implicitement par l’optimiseur de
requêtes ORACLE, et sont mis à jour automatiquement avec les lignes.
On crée des index, de manière générale, sur toutes les clés étrangères et sur les critères de recherche courants. Une
colonne virtuelle peut être indexée.
Les index concernant les clés primaires et secondaires (index UNIQUE) sont créés automatiquement lors de la création
de la contrainte avec comme nom, le nom de la contrainte. Pour les autres index, il faut utiliser le CREATE INDEX.
La mise en place des contraintes de clés primaires et d’unicité passe par la création implicite d’un index.
Syntaxe
Exemples
Création d’un index sur les clés étrangères REFART de la table LIGNESCDE.
Index créé.
Création d’un index sur la table CLIDIVERS sur les colonnes NOM et ADRESSE (critère de recherche) concaténées.
Index créé.
b. Suppression d’un index
Syntaxe
Il existe des index de différents types qui possèdent une incidence directe sur l’organisation physique des
données et ces choix relèvent de l’administration.
1. Les instructions
Les instructions SQL manipulent des expressions. Ces expressions font référence à des noms d’objets de la base, à
des constantes, comportent des appels à des fonctions standardisées et composent ces éléments avec des
opérateurs.
Des expressions logiques (conditions) permettent également de définir la portée des instructions.
a. Expressions
Les termes des expressions peuvent être :
● constantes caractères
exemple : ’chaîne de caractères’ ; ’Ecole Nantaise d’’Informatique’.
● constantes littérales date (format dépendant de la langue configurée pour l’instance)
exemple : ’15JAN94’
● constantes numériques
exemple : 10 ; 123.459 ; 1.26e+6
● noms d’attribut de table
exemple : CLIENTS.NOCLI, ARTICLES.DESIGNATION
● fonctions
exemple : SQRT(81) ; REPLACE(’IAGADIGI’, ’I’, ’OU’);SYSDATE
● pseudocolonnes
exemple : nomsequence.NEXTVAL ; ROWID.
b. Opérateurs
● arithmétiques + / * ( )
exemple : 1.15 * PRIX ; (2 * MTLIG)/5 ; SYSDATE +15
● sur les chaînes de caractères : concaténation ||
exemple : ’Monsieur’|| NOM
c. Conditions
Les conditions mettent en jeu des expressions, des opérateurs de comparaison et des opérateurs logiques.
Opérateurs de comparaison
● Comparaison simple
● Appartenance à un ensemble de valeurs
expression1 IN (expression2,...)
VRAI si expression1 apparaît au moins une fois dans la liste (expression2,...).
● Appartenance à un intervalle de valeurs
VRAI si expression1 se situe entre les bornes expression2 et expression3, bornes comprises.
● Comparaison par rapport à un format de chaîne de caractères
Le format peut inclure les métacaractères :
● "%" pour désigner une suite de 0 à n caractères
● "_" pour désigner un et un seul caractère.
Opérateurs logiques
Une expression NULL n’est ni VRAI ni FAUX.
● Négation d’une expression logique
NOT expression
● Combinaison d’expressions logiques
d. Fonctions
Il existe deux types de fonctions :
● Les fonctions scalaires (scalar function) qui portent sur une seule ligne : la fonction est exécutée et retourne
un résultat pour chaque ligne de la requête.
● Les fonctions sur un regroupement de lignes (group function) : la fonction est exécutée une fois et retourne
un résultat pour un ensemble de lignes de la requête. Ces fonctions sont appelées fonctions d’agrégat.
Si une fonction est appelée avec un argument NULL, la valeur retournée est NULL. Cette règle s’applique à
toutes les fonctions à l’exception de CONCAT, NVL et REPLACE, et des fonctions d’agrégat.
Notation des arguments des fonctions :
n expression numérique.
c expression caractère.
b expression logique.
Fonctions scalaires mathématiques
ABS (n)
valeur absolue de n.
CEIL (n)
premier entier supérieur ou égal à n.
COS (n)
cosinus.
COSH (n)
cosinus hyperbolique.
EXP (n)
e puissance n (e=2,71828183...).
FLOOR (n)
1 e r entier <=n.
LN (n)
logarithme népérien de n.
LOG (m,n)
logarithme de n base m.
MOD (n1,n2)
reste de n1/n2.
POWER (n1,n2)
n1 exposant n2.
ROUND (n1,[n2])
n1 arrondi à n2 positions décimales.
SIGN (n)
1 si n<0; 0 si n=0; +1 si n>0.
SIN (n)
sinus de n.
SINH (n)
sinus hyperbolique de n.
racine carrée de n.
TAN (n)
tangente de n.
TANH (n)
tangente hyperbolique de n.
TRUNC (n1,[n2])
n1 tronqué à n2 positions décimales.
La plupart des fonctions numériques retournent une valeur avec 38 chiffres significatifs. Cependant les
fonctions COS, COSH, EXP, LN, LOG, SIN, SINH, SQRT, TAN et TANH retournent une valeur avec seulement 36
chiffres significatifs.
Fonctions scalaires chaînes de caractères
ASCII (c)
code ASCII du 1e r caractère de c.
ASCIISTR (c)
la chaîne de caractères passée en paramètre est convertie au format de la table ASCII de la base.
CHR (n)
caractère ASCII du code n.
COMPOSE (c)
la chaîne de caractères passée en paramètre est convertie en format UNICODE.
CONCAT (c1, c2)
concaténation de c1 et c2.
DECOMPOSE (c)
cette fonction est valide uniquement pour les chaînes au format unicode et elle retourne une chaîne contenant les
différents caractères.
INITCAP (c)
renvoie c avec la première lettre de chaque mot en majuscule et les autres en minuscules.
INSTR (c1,c2[,n1[n2]])
ère
position de la nème occurrence (défaut 1 ) de c2 dans c1 à partir de la position n1 (1 par défaut).
INSTRB (c1,c2,n1[,n2])
identique à INSTR avec n1 et n2 en octets.
LENGTH (c)
LENGTHB (c)
identique à LENGTH retourne le nombre d’octets.
LOWER (c)
renvoie c en minuscules.
LPAD (c1,n[,c2])
renvoie c1 sur une longueur n complété à gauche avec c2 (par défaut ’ ’).
LTRIM (c1[,c2])
renvoie c1 avec suppression à gauche de tous les c2 (par défaut ’ ’).
NLS_INITCAP (c,’param’)
identique à INITCAP en tenant compte de param (code de pays).
NLS_LOWER (c,’param’)
identique à LOWER en tenant compte de param (code de pays).
NLSSORT (c)
séquence d’octets utilisés pour le tri de la chaîne c.
NLS_UPPER (c,’param’)
identique à UPPER en tenant compte de param (code de pays).
REPLACE (c1,c2,c3)
remplace dans c1 tous les c2 par c3 (c3 peut être nul).
RPAD (c1,n[,c2])
renvoie c1 sur une longueur n complété à droite avec c2 (par défaut ’ ’).
RTRIM (c1[,c2])
renvoie c1 avec suppression à droite de tous les c2 (par défaut ’ ’).
SOUNDEX (c)
représentation phonétique de c.
SUBSTR (c,n1[,n2])
renvoie une chaîne formée par n2 caractères de c à partir de la position n1.
SUBSTRB (c,n1[,n2])
identique à SUBSTR avec n1 et n2 en octets.
TRANSLATE (c1,c2,c3)
remplace dans c1 tous les c2 par c3 (c3 ne peut pas être nul).
TRIM ({{LEADING |TRAILING|BOTH c1} | {c1}} FROM c2 )
UNISTR (c)
la chaîne de caractères passée en paramètre est convertie au format unicode.
UPPER(c)
renvoie c en majuscules.
Fonctions scalaires dates
ADD_MONTHS (d,n)
date d plus n mois (n peut être négatif).
CURRENT_DATE
pour connaître la date et l’heure actuelle en prenant en compte le paramétrage de la zone horaire (TIME_ZONE) de
la session.
CURRENT_TIMESTAMP
pour connaître la date et l’heure relative à la plage horaire de la session. Cette fonction retourne une valeur de type
TIMESTAMP WITH TIME ZONE.
DBTIMEZONE
pour connaître la zone horaire en vigueur sur la base de données.
EXTRACT (format FROM d)
extrait un élément (jour, mois, année, heure, minute, seconde...) depuis un élément de type date ou bien un
intervalle de temps calculé à l’aide des fonctions NUMTODSINTERVAL ou NUMTOYMINTERVAL.
FROM_TZ (t, zone_horaire)
convertit une valeur de type TIMESTAMP en valeur de type TIMESTAMP WITH TIME ZONE.
LAST_DAY (d)
date du dernier jour du mois de d.
LOCALTIMESTAMP
pour connaître la date et heure courante par rapport à la zone horaire de la session. Cette fonction retourne une
valeur de type TIMESTAMP.
MONTHS_BETWEEN (d1,d2)
différence en mois entre les deux dates.
NEW_TIME (d,z1,z2)
la date d de la zone z1 est convertie en date de la zone z2.
NEXT_DAY (d,j)
date du prochain jour j à partir de d.
NUMTODSINTERVAL (n,format)
convertit le nombre n passé en paramètre au format date. Le second argument représente l’unité dans laquelle n est
NUMTOYMINTERVAL (n, format)
convertit le nombre n passé en paramètre au format mois, année. Le format indiqué en second paramètre permet de
préciser si le premier paramètre représente des mois (’MONTH’) ou des années (’YEAR’).
ROUND (d, format)
arrondit la date d à la date de début de l’élément donné en format le plus proche (Année, Mois, Jour, Heure...).
SESSIONTIMEZONE
pour connaître la zone horaire active dans la session actuelle.
SYSDATE
date système.
SYS_EXTRACT_UTC (d)
convertit une date et heure d’une zone horaire spécifique en date et heure au format UTC (Universal Time
Coordinated) c’estàdire à l’heure de Greenwich.
SYSTIMESTAMP
pour connaître la date et l’heure, y compris les fractions de secondes, en s’appuyant sur la zone horaire configurée
sur le serveur de base de données.
TRUNC (d, format)
tronque la date d au début de l’élément donné en format (Année, Mois, Jour, Heure...).
TZ_OFFSET (zone|format)
permet de connaître la zone horaire correspondant à la zone passée en paramètre.
Les formats de dates sont utilisés par les fonctions de conversion (TO_CHAR, TO_DATE) et les fonctions qui
manipulent les dates (TRUNC, ROUND). On trouve cidessous un tableau récapitulatif des principaux indicateurs de
format de dates qui peuvent être utilisés.
/ ’ . ; : ’texte’ Éléments de séparation présents dans le résultat.
D Numéro du jour dans la semaine (1 à 7). Cet indicateur est à utiliser
uniquement avec la fonction TO_DATE.
DAY Nom du jour de la semaine.
DD Numéro du jour dans le mois (1 à 31).
DDD Numéro du jour dans l’année (1 à 366).
DY Nom abrégé du jour de la semaine.
HH, HH12 Heure du jour (1 à 12).
HH24 Heure du jour (0 à 23).
IW Numéro de la semaine dans l’année (1 à 53) basé sur la norme ISO.
MI Minute (0 à 59).
MM Numéro du mois sur 2 caractères (1 à 12).
MONTH Nom du mois.
Q Numéro du trimestre (1 à 4).
RM Numéro du mois en chiffre romain (I à XII).
SS Secondes (0 à 59).
SSSS Nombre de secondes depuis minuit (0 à 86399).
WW Numéro de la semaine dans l’année. La semaine n°1 commence le premier jour
de l’année et dure 7 jours.
W Numéro de la semaine dans le mois (1 à 5). La première semaine du mois
commence le premier jour du mois et se termine le septième jour.
YYYY Année sur 4, 3, 2 ou 1 chiffre(s).
YYY
YY
Y
Fonctions scalaires de conversion
BIN_TO_NUM (expr[, ...])
conversion d’un ensemble de nombres binaires en son équivalent décimal.
CHARTOROWID (char)
conversion de chaîne de caractères de forme ’nobloc.nolig.nofich’ en type ROWID. Cette pseudocolonne représente
l’adresse physique de la ligne dans la base Oracle.
CONVERT (char,destination[,source])
conversion de jeu de caractères.
source ou destination
US7ASCII (défaut), WE8DEC (Dec Europe), WE8JHP (HP Europe), F7DEC (français DEC), WE8EBDCIC500 (IBM Europe
Code page 500), WE8PC850 (IBM PC Code page 850), WE8ISO8859P1 (ISO88591 Europe 8 bits).
HEXTORAW (char)
conversion d’une valeur hexadécimale contenue dans une chaîne de caractères en une expression binaire de type
RAW.
RAWTOHEX (raw), RAWTONHEX (raw)
fonction inverse de la précédente.
ROWIDTOCHAR(rowid), ROWIDTONCHAR (rowid)
fonction inverse de CHARTOROWID.
TO_CHAR (caractère)
conversion d’une chaîne de caractères au format NCHAR, NVARCHAR2, CLOB ou NCLOB dans le jeu de caractères
utilisée dans la base de données.
conversion numérique en caractères.
format : chaîne de caractères représentant le format numérique (les éléments possibles de cette chaîne de
caractères sont présentés dans le tableau des formats de date vu précédemment).
param : convention de pays.
TO_CHAR (d, format)
conversion d’une date en chaîne de caractères.
TO_CLOB (chaîne)
conversion d’une chaîne de caractères ou de type LOB au format CLOB.
TO_DATE (char, format)
fonction inverse de TO_CHAR (caractère en date).
TO_DSINTERVAL (chaîne)
conversion d’une chaîne de caractères en données de type intervalle Jour/Seconde.
TO_NCHAR (c)
conversion d’une chaîne de caractères dans le jeu de caractères national (deuxième jeu de caractères de la base).
TO_NCHAR (d,format)
conversion d’une date en chaîne, dans le jeu de caractères national.
TO_NCHAR (n)
conversion d’un nombre en chaîne de caractères dans le jeu de caractères national.
TO_NCLOB (c)
conversion d’une chaîne de caractères en élément de type NCLOB.
TO_NUMBER (char)
conversion d’une chaîne de caractères en numérique.
TO_TIMESTAMP (c[,format])
conversion d’une chaîne de caractères en élément de type TIMESTAMP en s’appuyant sur le format de la date indiqué
en second paramètre.
TO_TIMESTAMP_TZ (c[,format])
conversion d’une chaîne de caractères en élément de type TIMESTAMP WITH TIME ZONE en s’appuyant sur le format
de la date indiqué en second paramètre.
TO_YMINTERVAL (chaîne)
conversion d’une chaîne de caractères en données de type intervalle Mois/Année.
Exemple d’utilisation de fonctions de conversion
Dans l’exemple cidessous, la fonction SYSDATE permet de connaître la date et l’heure actuelle puis ces informations sont
affichées proprement à l’aide de la fonction de conversion de TO_CHAR. Pour convertir la date en chaîne de caractères, on
utilise un format de conversion dont les indicateurs sont donnés dans le tableau précédent.
Fonctions de comparaisons
NULLIF (expr1, expr2)
Compare expr1 et expr2. Si les deux expressions sont égales, alors la valeur NULL est retournée, sinon expr1 est
retournée. Il n’est pas possible de préciser la valeur NULL dans expr1.
Fonctions scalaires diverses
BITAND (arg1, arg2)
effectue une opération ET entre les deux arguments bit par bit.
COALESCE (expr,[, ...])
retourne la première expression non nulle passée en paramètre.
DECODE (colonne, valeur 1, resul1 [,valeur2, resul2 ...],[défaut])
si colonne a la valeur valeur 1, la forme sera resul1.
DUMP (exp[,format[,départ[longueur]]])
les formats possibles sont :
8 (le résultat est exprimé en octal),
10 (le résultat est exprimé en décimal),
16 (le résultat est exprimé en hexadécimal),
17 (le résultat est exprimé en caractères).
Les options départ et longueur permettent de préciser la partie de la chaîne à traiter.
GREATEST (exp[,exp...])
renvoie la plus grande des expressions.
LEAST (exp[,exp......])
renvoie la plus petite des expressions.
NVL (exp1, exp2)
si expression1 est NULL renvoie expression2.
NVL2 (exp1, exp2, exp3)
si expression1 est NULL, alors la fonction NVL2 retourne expression2, sinon c’est expression3 qui est retournée. Les
expressions 2 et 3 peuvent être de n’importe quel type de données à l’exception du type LONG.
UID
numéro identificateur de l’utilisateur.
nom de l’utilisateur.
USERENV (opt)
renvoie des caractéristiques de l’environnement.
opt : ENTRY ID ; SESSION ID ; TERMINAL ; LANGUAGE ; LANG ; ISDBA ; CLIENT_INFO.
VSIZE (exp)
nombre d’octets stockés pour exp.
WIDTH_BUCKET (expr, mini, maxi, n)
construit n intervalles équivalents sur la plage mini à maxi puis indique dans quel intervalle se trouve chaque
expression.
2. Création de lignes
L’ajout d’une ligne à la table est réalisé si les contraintes sont respectées. Si les noms des colonnes à valoriser ne
sont pas cités, une expression doit être donnée pour chaque colonne dans l’ordre des définitions de colonne faites
lors de la création de la table. Aucune colonne ne peut être omise.
Syntaxe
Exemples
Création d’un client (les colonnes non citées sont à NULL).
1 ligne créée.
SQL>
Valorisation de toutes les colonnes pour un article :
1 ligne créée.
SQL>
Valorisation d’une ligne de commande, avec saisie de variable par SQLPLUS (première colonne, voir chapitre SQL*Plus) et
expression pour le calcul de la quantité (dernière colonne) :
1 ligne créée.
SQL>
Pour insérer une valeur NULL dans une colonne, il faut remplir toutes les colonnes pour lesquelles on possède
une valeur, à l’aide de la syntaxe indiquée dans l’exemple cidessus (les autres colonnes auront la valeur
NULL).
L’instruction INSERT permet d’ajouter une ou plusieurs lignes dans la table de destination.
Si l’insertion d’une ligne d’informations est le fonctionnement le plus fréquent, il est également possible d’ajouter
plusieurs lignes dans la table. Ces lignes insérées de façon massive sont extraites de la base de données par une
requête de type SELECT.
Ce processus facilite le transfert de données d’une table à une autre.
Syntaxe
Exemple
Extraction de la liste des clients qui habitent Nantes vers une nouvelle table.
3. Suppression de lignes
Instruction DELETE
L’instruction DELETE supprime toutes les lignes d’une table. Si la clause WHERE est utilisée, seules les lignes pour
lesquelles la condition est vraie sont supprimées.
Syntaxe
Exemples
Suppression d’un article facture :
1 ligne supprimée.
Tentative de suppression d’articles valant entre 153 et 306 euros. Certains de ces articles sont référencés dans d’autres
tables, d’où l’erreur :
Suppression des lignes référençant les articles :
1 ligne supprimée.
SQL>
Suppression des articles valant entre 153 et 306 euros (AB10, AB22) :
2 ligne(s) supprimée(s).
SQL>
Suppression des articles dont la désignation commence par "Ca" (AA00;AB03) :
Suppression des articles dont la quantité en stock n’est pas valorisée :
2 ligne(s) supprimée(s).
Instruction TRUNCATE
L’instruction TRUNCATE permet de supprimer toutes les lignes d’une table et de reprendre les conditions de stockage
adoptées lors de la création de la table.
Syntaxe
Exemple
Suppression des produits.
4. Modification de lignes
L’instruction UPDATE permet de remplacer, dans une table, la valeur des colonnes spécifiées par des expressions. Si
aucune clause WHERE n’est spécifiée, la mise à jour est réalisée pour toutes les lignes de la table. Dans le cas
contraire, seules les lignes pour lesquelles la condition spécifiée dans la clause WHERE est vérifiée sont mises à jour.
Syntaxe
Exemples
Mise à jour de la quantité en stock à 15 pour l’article AB10 :
Augmentation de 10% du prix pour les articles dont la référence commence par AB :
Passage de la désignation en majuscules et élimination des espaces en fin de référence pour tous les articles :
5. Extraction des données
L’instruction SELECT permet d’afficher les données d’une table, vue ou synonyme.
Syntaxe
* signifie toutes les colonnes.
Exemple
Visualisation de toute la table ARTICLES :
Table initiale :
Références ayant moins de 20 unités en stock :
6. Contrôle des transactions
La transaction permet de s’assurer que l’ensemble des instructions incluses dans celleci sera réalisé dans sa totalité
ou pas du tout.
Une seule transaction est active à un instant donné. Cette transaction se termine lors de l’utilisation de l’instruction
COMMIT ou ROLLBACK. Une nouvelle transaction débute lors de la première instruction DML suivante.
Chaque transaction permet également d’assurer la cohérence des données vues par chaque utilisateur connecté au
SGBDR. En effet toutes les modifications faites sur les données au cours d’une transaction se font par rapport à l’état
de ces données au début de la transaction. Les modifications apportées sur les données au cours d’une transaction
exécutée par un utilisateur ne seront visibles des autres utilisateurs qu’après la validation (COMMIT) de cette
transaction.
a. Validation de la transaction
Les modifications de lignes depuis le dernier COMMIT ou CONNECT deviennent définitives.
Il est également possible de mettre fin à une transaction en succès simplement en exécutant une instruction du DDL,
comme par exemple une commande CREATE, ALTER ou DROP. En effet, les instructions du DDL ne peuvent pas
participer à la transaction. La transaction en cours est donc finie avec succès, puis l’instruction DDL est exécutée et
une nouvelle transaction débute. Cette nouvelle transaction concernera les instructions DML qui suivent. Cette
validation de transaction est faite de façon implicite et peut être la source d’erreur dans la compréhension du
mécanisme des transactions.
Syntaxe
COMMIT;
b. Annulation des modifications
Les modifications de lignes faites depuis le dernier COMMIT, CONNECT ou le SAVEPOINT mentionné sont annulées.
Si le ROLLBACK indique un SAVEPOINT, la transaction en cours est toujours active après l’exécution de l’instruction.
Syntaxe
c. Déclaration d’un point de contrôle
Un point de contrôle permet de mémoriser un état des données au cours de la transaction. La pose d’un SAVEPOINT
permet d’annuler les modifications faites après la pose de celuici.
La transaction en cours est toujours active après la pose du SAVEPOINT.
Syntaxe
SAVEPOINT savepoint;
Exemple
Savepoint créé.
4 ligne(s) supprimée(s).
Savepoint créé.
SQL> insert into clients (nocli, nomcli, ville)
2 values (111,’DURAND’,’RENNES’);
1 ligne créée.
7 ligne(s) sélectionnée(s).
SQL> commit;
Validation effectuée.
SQL>
d. Accès simultané aux données
Deux sessions (session 1 et session 2) sont ouvertes sous le même nom d’utilisateur.
Session 1 : insertion d’une ligne dans la table COMMANDES. La ligne insérée est visible dans la transaction.
1 ligne créée.
SQL>
Session 2 : Pas de COMMIT dans la session 1 après l’insertion. La ligne insérée n’est pas visible dans la session 2.
Insertion d’une ligne dans la table COMMANDES.
1 ligne créée.
SQL>select NOCDE, NOCLI, DATECDE, ETATCDE from COMMANDES ;
SQL>
Session 1 : COMMIT
SQL>commit ;
Validation effectuée.
SQL>select NOCDE, NOCLI, DATECDE, ETATCDE from COMMANDES ;
SQL>
Session 2 : la ligne insérée à l’étape 1 dans la transaction est maintenant visible dans la session 2.
6 ligne(s) sélectionnée(s).
SQL>commit ;
Validation effectuée.
SQL>select NOCDE, NOCLI, DATECDE, ETATCDE from COMMANDES ;
NOCDE NOCLI DATECDE ET
--------------------------------------
1301 15 20/11/98 EC
1210 15 12/11/98 SO
1250 35 14/11/98 EC
1230 35 14/11/98 EC
2000 35 22/11/98 EC
2001 15 22/11/98 EC
6 ligne(s) sélectionnée(s).
SQL>
e. Vérification des contraintes en fin de transaction
Dans certains cas, il peut être nécessaire de vérifier les contraintes d’intégrité en fin de transaction. Pour pouvoir
profiter de cette fonctionnalité, il est nécessaire de préciser, lors de la mise en place de la contrainte d’intégrité, que
sa vérification est différée en fin de transaction (INITIALLY DEFERRED), ou bien si, au contraire, il est possible de
demander dans certains cas la validation de la contrainte en fin de transaction (DEFERRABLE). Par défaut, les
contraintes d’intégrité sont vérifiées dès la mise en place des valeurs dans les tables et il n’est pas possible de
déplacer cette vérification en fin de transaction.
La syntaxe exacte de mise en place de ces états de contrainte est expliquée dans le titre Création d’une
table Complément sur les contraintes dans ce chapitre.
Ainsi, dans l’exemple présenté ciaprès, il est nécessaire de posséder un abonnement pour pouvoir être membre et
chaque abonnement doit être possédé par un et un seul membre.
La mise en place de cette liaison 11 entre les 2 tables va s’effectuer en mettant en place une contrainte de
référence entre les 2 tables. Chaque occurrence d’abonnement référence une et une seule occurrence de membre et
Mise en place des contraintes de clé étrangère
Insertion de données
1. Opérations
a. Restriction
La restriction permet de n’obtenir que les lignes répondant à une condition.
L’opération σ s (cond) se traduit par :
Exemple
Restriction sur le numéro de commande dans la table CDE = σ COMMANDES (NOCDE = 100) :
SQL>
b. Calculs élémentaires
Le calcul élémentaire permet d’obtenir des colonnes calculées pour chaque ligne. L’opération π S (col, ..., nvcol = exp)
se traduit par :
Exemple
Calcul de la valeur de stock π ARTICLES(REFART, DESIGNATION, VALSTK = (PRIXHT * QTESTK)) :
8 ligne(s) sélectionnée(s).
SQL>
c. Projection
La projection a pour but d’éliminer les colonnes inutiles. Elle se fait en SQL en ne citant que les colonnes voulues
dans le SELECT.
Les projections de regroupement peuvent s’effectuer à l’aide de deux syntaxes :
ou
La première syntaxe (DISTINCT) permet de n’afficher qu’une occurence de ligne dans le cas où la requête ramène
plusieurs lignes identiques. La deuxième syntaxe (GROUP BY) est utilisée lorsque l’on souhaite réaliser une
projection de groupe avec le calcul d’agrégats sur les lignes regroupées.
Le mot clé DISTINCT permet uniquement d’effectuer l’affichage de valeurs distinctes, tandis que le mot clé GROUP BY
effectue en premier lieu un regroupement. Cette opération de regroupement rend possible les calculs d’agrégats
mais demande bien sûr un peu plus de temps au niveau du processeur du serveur.
Exemples
Affichage d’une ligne par nom client :
NOMCLI
------------------------------
DUPONT S.A.
Etb LABICHE
DUBOIS Jean
BERNARD S.A.
DUBOIS Jean
LAROCHE
6 ligne(s) sélectionnée(s).
NOMCLI
------------------------------
BERNARD S.A.
DUBOIS Jean
DUPONT S.A.
Etb LABICHE
LAROCHE
SQL> select NOMCLI from CLIENTS group by NOMCLI;
NOMCLI
------------------------------
BERNARD S.A.
DUBOIS Jean
DUPONT S.A.
Etb LABICHE
LAROCHE
SQL>
Regroupement par NOM et VILLE.
NOMCLI VILLE
-----------------------------------------
BERNARD S.A. PARIS
DUBOIS Jean NANTES
DUBOIS Jean TOURS
DUPONT S.A. NANTES
6 ligne(s) sélectionnée(s).
SQL>
d. Calculs d’agrégats
Les projections de calcul d’agrégats permettent des calculs statistiques sur des regroupements introduits par GROUP
BY.
L’opération π S (col, ..., nvcol = calcul statistique) se traduit par :
La liste de colonnes projetées (derrière le SELECT) doit être identique à la liste de colonnes de regroupement
(derrière le GROUP BY).
Les noms des colonnes peuvent apparaître dans des calculs élémentaires ; dans ce cas le regroupement doit porter
sur les mêmes expressions.
e. Fonctions de GROUPE
coln
Colonne numérique.
colonne
Colonne de tout type.
AVG (coln)
Moyenne des valeurs de colonne.
COUNT (colonne)
Pour chaque regroupement, nombre de lignes regroupées où colonne est non NULL.
COUNT (*)
Pour chaque regroupement, nombre de lignes regroupées.
MAX (colonne)
Valeur maximum de la colonne pour chaque regroupement.
MIN (colonne)
Valeur minimum de la colonne pour chaque regroupement.
STDDEV (coln)
Écarttype des valeurs de colonne pour chaque regroupement.
SUM (coln)
Somme des valeurs de colonne pour chaque regroupement.
VARIANCE (coln)
Variance des valeurs de colonne pour chaque regroupement.
Cœ fficient de corrélation entre les 2 colonnes.
COVAR_POP (col1, col2)
Covariance d’une population.
COVAR_SAMP (col1, col2)
Covariance d’un échantillon.
CUME_DIST (col, pourcentage)
Distribution cumulative.
DENSE_RANK (col)
Numéro d’ordre d’une ligne dans un ensemble ordonné de lignes.
FIRST (col) LAST (col)
Retourne la première (dernière) ligne ordonnée par rapport à un critère tri (DENSE_RANK par exemple).
GROUP_ID
Distingue les groupes dupliqués apparus suite à l’application de la clause GROUP BY.
GROUPING (expr)
Permet d’identifier les lignes de cumul lorsque les instructions ROLLUP ou CUBE sont utilisées.
GROUPING_ID (expr)
Comme pour la fonction GROUPING, permet d’identifier si la ligne est ou non le résultat d’une commande ROLLUP ou
CUBE.
PERCENTILE_CONT (expr)
Distribution inverse continue.
PERCENTILE_DISC (expr)
Distribution inverse discrète.
PERCENT_RANK (expr)
Similaire à CUME_DIST.
RANK (expr)
Calcule le rang d’une valeur dans un groupe de valeurs.
REGR_(expr)
Calcul de la régression linéaire.
STDDEV_POP (expr)
Écarttype d’une population.
STDDEV_SAMP (expr)
VAR_POP (expr)
Variance d’une population.
VAR_SAMP (expr)
Variance d’un échantillon.
Dans le cas où le calcul d’agrégats porte sur une colonne particulière, les valeurs NULL de cette colonne ne
sont pas prises en compte pour les calculs.
Oracle dispose de quelques autres fonctions de calculs d’agrégats qui sont spécialisées dans le calcul
statistique.
Exemples
Nombre de clients par ville. L’attribut ville ayant été défini de type CHAR(30), il faut éliminer les éventuels espaces à droite
pour que le regroupement se fasse bien sur les caractères significatifs de la valeur de la colonne.
RTRIM(VILLE) COUNT(*)
--------------------------------------------
LE MANS 1
NANTES 3
PARIS 1
TOURS 1
SQL>
Prix le plus élevé et moyenne des quantités en stock par famille d’articles (deux premiers caractères de la référence) :
9 ligne(s) sélectionnée(s).
SU MAX(PRIX) AVG(QTESTK)
-- ---------- -----------
AA 8
AB 1650 33,25
CD 500 13,5
ZZ 500 12,5
SQL>
f. Fonctions analytiques
AVG
Moyenne.
CORR
Cœ fficient de corrélation.
COVAR_POP
Covariance d’une population.
COVAR_SAMP
Covariance d’un échantillon.
COUNT
Comptage.
CUME_DIST
Distribution cumulative.
DENSE_RANK
Calcule le rang d’une ligne dans un groupe ordonné de lignes.
FIRST
Permet d’obtenir la première ligne depuis un jeu de résultats trié.
LAST
Permet d’obtenir la dernière ligne depuis un jeu de résultats trié.
FIRST_VALUE
Première valeur d’un ensemble de résultats triés.
LAST_VALUE
Dernière valeur d’un ensemble de résultats triés.
LAG
Permet d’accéder à plus d’une ligne de façon simultanée.
LEAD
Fonction similaire à LAG.
MAX
Plus grand élément.
MIN
NTILE
Permet de diviser une ligne de résultat en petits groupes parfaitement identifiés par leur numéro d’ordre.
PERCENT_RANK
Distribution cumulative.
PERCENTILE_CONT
Distribution inverse continue.
PERCENTILE_DISC
Distribution inverse discrète.
RANK
Rang d’une valeur au sein d’un groupe.
RATIO_TO_REPORT
Calcule le rapport entre une valeur et la somme d’un ensemble de valeurs.
REGR
Régression linéaire.
ROW_NUMBER
Permet de générer un numéro unique pour chaque ligne.
STDDEV
Ecarttype.
STDDEV_POP
Ecarttype sur une population.
STDDEV_SAMP
Ecarttype sur un échantillon.
SUM
Somme.
VAR_POP
Variance d’une population.
VAR_SAMP
Variance d’un échantillon.
VARIANCE
Variance.
Dans l’exemple ciaprès, la requête permet de lister tous les articles dont la référence commence par AB et d’afficher en
face de chacun d’eux la référence de l’article le moins cher.
SQL>
g. Restrictions sur agrégat
Lorsque l’on souhaite restreindre le nombre de lignes renvoyées par une requête comportant un calcul d’agrégats, il
est possible d’utiliser la clause HAVING. La syntaxe est alors :
La condition peut alors contenir une fonction statistique. Les expressions utilisées dans la clause HAVING peuvent
faire référence à des critères de regroupement ou des calculs d’agrégats.
Exemple
Affichage des informations statistiques des familles d’articles dont le prix minimum est supérieur à 300 euros.
SU MAX(PRIX) MIN(PRIX)
-- --------- ---------
CD 735,4 735,4
ZZ 500 500
SQL>
h. Produit cartésien
Le produit cartésien permet d’obtenir l’association de chaque ligne d’une table avec chaque ligne d’autres tables.
L’opération S X T se traduit par :
Si des colonnes portent le même nom dans les deux tables, on préfixe le nom de la colonne par le nom de la table.
Le nom complet de la colonne est alors : nomtable.nomcolonne.
Exemple
Création et valorisation d’une table DEPOTS. Simulation de l’affectation de chaque article à chaque dépôt :
i. Jointures
La jointure est une restriction sur le produit cartésien afin de lier chaque ligne d’une table avec des lignes d’une
autre table en respectant une condition.
L’opération S JOIN (cond) T se traduit par :
Exemple
Jointure naturelle entre COMMANDES et CLIENTS :
SQL>
Depuis la version 9i, Oracle supporte les jointures exprimées dans une syntaxe compatible avec la norme ANSI. Bien
que cette façon d’écrire soit normalisée, elle est souvent moins utilisée que la syntaxe présentée précédemment car
les informations sont moins lisibles. Néanmoins les générateurs de requêtes utilisent cette syntaxe normalisée.
SQL>
L’avantage de la syntaxe normalisée est par contre très net lors de la mise en place des jointures naturelles entre
les tables, car il n’est alors plus nécessaire de citer la condition de jointure.
SQL>
j. Jointures externes
La jointure externe (outer join) est une extension de la jointure, qui permet d’obtenir en plus des lignes répondant à
la condition, les lignes de l’une des tables qui n’y répondent pas. Il suffit d’ajouter l’opérateur (+) dans la condition,
derrière la colonne de la table dont les lignes peuvent ne pas apparaître dans le résultat.
Exemple
Liste des clients avec éventuellement leurs commandes.
8 ligne(s) sélectionnée(s).
SQL>
k. Union, intersection, différence
Ces opérateurs permettent d’obtenir dans une requête des lignes provenant de requêtes distinctes mais de même
forme (même nombre de colonnes, même type dans le même ordre).
Les opérations S {∪/∩/} T se traduisent par :
L’opérateur UNION ALL permet de retrouver toutes les lignes issues des requêtes sans élimination des doublons.
Exemple
Regroupements des lignes de CLIENTS et CLIDIVERS :
NOCLI NOMCLI
--------- ------------------------------
15 DUPONT S.A.
20 Etb LABICHE
35 DUBOIS Jean
36 BERNARD S.A.
123 DUPOND and Co
138 DUBOIS Jean
152 LAROCHE
556 DUBOIS Jean
567 OEYSTER Ltd
9 ligne(s) sélectionnée(s).
NOMCLI
------------------------------
BERNARD S.A.
DUBOIS Jean
DUPOND and Co
DUPONT S.A.
Etb LABICHE
LAROCHE
OEYSTER Ltd
7 ligne(s) sélectionnée(s).
SQL>
2. Traitement du résultat
Le résultat des requêtes précédentes peut servir à plusieurs usages :
● affichage trié ou non,
● valorisation d’une table intermédiaire,
● création d’un fichier externe à la base.
a. Le tri
Pour obtenir un résultat trié, on utilise la clause ORDER BY en fin de commande SELECT.
Par défaut, le tri est croissant et l’ordre est déterminé par les paramètres nationaux de l’environnement de
l’utilisateur (paramètre NLS_SORT). Le tri décroissant est obtenu à l’aide de l’option DESC de la clause ORDER BY. Il
est possible pour l’utilisateur, s’il en possède le privilège, de modifier le paramètre NLS_SORT en cours de session.
L’ordre de tri peut également être spécifié en indiquant dans la clause ORDER BY le numéro d’ordre correspondant
dans la clause SELECT à la colonne servant au tri.
Exemple
Affichage des articles triés par famille et prix décroissant.
REFA PRIX
---- ---------------
0 0
AB
AB10 1500
AB22 1250,1
AB03 150
CD50 735,4
ZZZZ
ZZ01 500
8 ligne(s) sélectionnée(s).
PRIX SU
--------- --
0 AA
AB
1500 AB
1250,1 AB
150 AB
735,4 CD
ZZ
500 ZZ
8 ligne(s) sélectionnée(s).
SQL>
b. La sauvegarde
Par SQL
Il est possible de sauvegarder le résultat d’une requête dans une table, afin de pouvoir l’utiliser dans une autre
requête.
Deux méthodes sont utilisables :
● créer la table puis y insérer des lignes résultant de la requête,
● créer la table à partir de la requête.
Première méthode
Syntaxes
Cette méthode permet de choisir les types de colonnes, les valeurs par défaut, et de mettre en place des contrôles
en utilisant les contraintes.
Table créée.
SQL>
SQL> insert into CLI
2 select to_char(NOCLI, ’009’), substr(NOMCLI, 1, 10)
3 from CLIENTS where VILLE like ’PARIS%’;
1 ligne créée.
NOCL NOMCLI
---- ----------
036 BERNARD S.
Table supprimée.
SQL>
Deuxième méthode
Syntaxe
Par cette méthode plus rapide, les noms et les types des colonnes de la nouvelle table sont dérivés de ceux des
colonnes projetées dans le SELECT.
Exemple
Sauvegarde de la restriction "Clients de LoireAtlantique" dans une table CLI44 :
Table créée.
NOCLI NOMCLI
--------- ------------------------------
15 DUPONT S.A.
20 Etb LABICHE
35 DUBOIS Jean
SQL> desc CLI44
Name Null? Type
------------------------- -------- --------------
NOCLI NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
SQL>
Par SQLPLUS
Sauvegarde du résultat de la requête dans un fichier ASCII.
Syntaxe
Exemple
Création d’un fichier séquentiel ASCII fic.lst contenant les données de la table CLIENTS.
Les tables temporaires
En plus des tables permanentes, Oracle offre la possibilité de créer des tables temporaires pour stocker des
informations le temps d’une session ou d’une transaction. Les données stockées dans une table temporaire créée
avec l’ordre CREATE GLOBAL TEMPORARY TABLE, sont accessibles uniquement depuis la session qui a créé les
données. En fait chaque session ne voit que ses propres données et une instruction TRUNCATE TABLE sur une table
temporaire permet simplement de supprimer toutes les données issues de la session qui lance l’ordre TRUNCATE.
La spécificité de cette table temporaire réside dans le fait que les données insérées dans cette table ne restent
présentes que le temps de la transaction. La table, quant à elle, reste bien sûr en place et il est possible de l’utiliser
dans les autres transactions. Si l’on souhaite que les données insérées dans cette table soit stockées de façon plus
persistante, il faut utiliser la clause ON COMMIT PRESERVE ROWS lors de la création de la table temporaire globale.
Ainsi, les informations insérées dans cette table seront visibles à travers toutes les transactions pendant la durée de
la session de l’utilisateur Oracle qui a inséré les informations dans la table.
Syntaxe
Exemple
Création d’une table temporaire globale destinée à recevoir les numéro et nom de certains clients.
Des données sont ajoutées à la table temporaire. Ces données sont le résultat d’une commande de type SELECT, qui
permet de connaître le numéro et le nom des clients de chaque commande.
Depuis la même session, on interroge la table temporaire pour connaître son contenu :
Depuis une autre session, on interroge la même table temporaire pour connaître son contenu :
La création de la même table avec l’option ON COMMIT PRESERVE ROWS :
c. Énumérer toutes les possibilités d’un calcul d’agrégats
Un calcul d’agrégats porte toujours sur le regroupement indiqué par la clause GROUP BY. Il est parfois nécessaire
d’effectuer un regroupement plus large afin de connaître d’autres valeurs. Par exemple, on souhaite connaître le
montant de chaque commande et le montant de toutes les commandes passées par un client. Pour mener à bien ces
calculs en une seule étape, il faut utiliser les mots clés ROLLUP et CUBE.
ROLLUP
Permet de faire des regroupements de plus en plus généraux.
CUBE
Permet de réaliser le calcul demandé sur tous les regroupements possibles.
Syntaxe
Le fonctionnement de ces deux mots clés va être expliqué au travers des exemples suivants.
Exemple
Dans l’exemple cidessous, ROLLUP permet de calculer le total pour chaque client ainsi que le montant total des
commandes tous clients confondus :
L’instruction CUBE permet quant à elle d’explorer toutes les combinaisons possibles.
3. MERGE
Cette instruction permet de fusionner, en une seule requête, une opération de mise à jour (INSERT, UPDATE, DELETE)
sur une table.
Les informations, qui servent de base à l’exécution de l’ordre DML, peuvent provenir d’une ou de plusieurs tables.
Toutefois, la même ligne d’informations ne peut pas participer en tant que source et destination de l’instruction
MERGE.
Comme une ligne ne peut pas être à la fois source et destination de la commande MERGE, la première étape va consister à
créer une table temporaire qui va contenir les numéros d’employés et leur âge.
Enfin les données de la table des employés sont mises à jour.
Le nouveau contenu de la table des employés est alors :
L’utilisation de cette instruction permet d’éviter l’exécution de nombreuses requêtes telles que INSERT, UPDATE ou
bien DELETE.
Il n’est pas possible de mettre plusieurs fois à jour une ligne au cours d’une seule instruction MERGE.
Syntaxe
INTO
Permet de spécifier la table cible de l’instruction MERGE et donc des opérations INSERT, UPDATE et DELETE.
USING
Permet de spécifier la façon dont les données qui participent à cette instruction sont sélectionnées ; il s’agit d’une
requête de type SELECT ou d’un nom de table ou de vue.
ON
Permet de faire une jointure entre les informations déjà présentes dans la table cible et celles issues de la source. En
fonction de cette jointure, l’action sera soit une mise à jour (WHEN MATCHED) ou bien une insertion (WHEN NOT
MATCHED).
WHEN MATCHED
Permet de définir l’action de mise à jour à effectuer ou bien éventuellement de suppression.
Permet de définir une insertion à réaliser sur la table cible.
1. Les objets
a. Les objets View (vue)
Les vues sont des tables virtuelles présentant le résultat d’un SELECT.
L’un des intérêts de l’utilisation des vues vient du fait que la vue ne stocke pas les données, mais fait référence à
une ou plusieurs tables d’origine à travers une requête SELECT, requête qui est exécutée chaque fois que la vue est
référencée. De ce fait, toute modification de données dans les tables d’origine est immédiatement visible dans la vue
dès que celleci est à nouveau exécutée.
Les cas d’utilisation des vues sont multiples :
● Cacher aux utilisateurs certaines colonnes ou certaines lignes en mettant à leur disposition des vues de
projection ou de restriction. Ceci permet de fournir un niveau de sécurité supplémentaire.
● Simplifier l’utilisation de tables comportant beaucoup de colonnes, beaucoup de lignes, ou des noms
complexes, en créant des vues avec des structures plus simples et des noms plus explicites.
● "Sauvegarder" des requêtes fréquemment utilisées sous un nom.
● Simplifier la saisie des instructions SQL pour les utilisateurs en masquant les jointures fréquemment utilisées.
Les vues, une fois créées, sont utilisables comme des tables dans les instructions DML, INSERT, SELECT, UPDATE,
DELETE. Toutefois les mises à jour ne sont pas possibles si la vue comporte :
● des instructions ensemblistes (UNION, INTERSECT, MINUS),
● des fonctions de groupe,
● des clauses GROUP BY, CONNECT BY, START WITH.
Une vue définie par une jointure supporte les instructions INSERT, UPDATE, DELETE si elle référence dans sa
définition une table dont la (les) colonne(s) clé primaire apparaît (apparaissent) dans la liste des colonnes projetées
de la jointure et si les instructions INSERT, UPDATE, DELETE portent sur cette table.
Création
Syntaxe
OR REPLACE
Permet le remplacement de la description par la nouvelle requête si la vue existe déjà. En effet, la définition d’une
vue ne peut être modifiée partiellement.
FORCE | NO FORCE
READ ONLY
Interdit toute insertion, modification, suppression de données à travers la vue.
Vérifie, lors de l’insertion ou de la modification de lignes dans la vue, que les lignes insérées ou modifiées sont
visualisables dans cette vue.
Compilation
Syntaxe
La compilation de la vue permet de valider la requête qui lui est associée et de détecter au plus tôt d’éventuelles
références incorrectes dans celleci. Ceci est en particulier utile après modification de la structure d’une des tables
sousjacentes de la vue. Si la compilation de la vue provoque une erreur, tous les autres objets de la base
dépendant de cette vue deviennent invalides.
Exemple
Vue retournant les clients du département 44. L’option WITH CHECK OPTION empêche toute insertion de client
n’appartenant pas à ce département.
Vue créée.
SQL> select NOCLI, substr(NOMCLI,1,12), CODE_POSTAL,
2 substr(VILLE,1,12) from V_CLI44;
1 ligne créée.
7 ligne(s) sélectionnée(s).
SQL>
La vue V_CLICMD sauvegarde la jointure CLIENTS/ COMMANDES. La vue V_CLICMD44 permet de faire une restriction sur
les clients du département 44. La vue V_CLICMD est ensuite rendue invalide suite à la suppression d’une table référencée
dans sa clause SELECT. La vue V_CLICMD44 est automatiquement invalidée.
Vue créée.
Vue créée.
Table supprimée.
SQL>
Insertion dans une vue basée sur une jointure.
1 ligne créée.
SQL>
Suppression
Syntaxe
Les objets qui référencent la vue supprimée deviennent invalides.
Les vues en ligne
Il est possible de définir une vue directement à l’intérieur d’une requête sans qu’il soit nécessaire de passer par une
commande CREATE VIEW. Cette possibilité est intéressante car elle permet de définir simplement une vue dont
l’utilisation est limitée.
Exemple
La vue définie en ligne permet de connaître le montant de chaque commande. Elle est référencée dans la requête par l’alias
de table LCDE. La requête affiche les informations relatives à chaque client.
b. Les objets Schema
Un schéma est un ensemble de tables, vues et privilèges regroupés sous un même nom (celui de l’utilisateur).
L’utilisation explicite d’un schéma avec l’instruction CREATE SCHEMA AUTHORIZATION permet d’étendre la notion de
transaction aux instructions DDL de création de table, de vue et d’affectation de privilège GRANT.
Si l’une des instructions DDL spécifiées dans le CREATE SCHEMA AUTHORIZATION échoue, l’ensemble des instructions
est annulé.
Le nom de SCHEMA utilisé dans l’instruction est celui associé à l’utilisateur (USER) qui a ouvert la session en cours.
Syntaxe
Exemple
Instruction CREATE SCHEMA AUTHORIZATION exécutée sans erreur. Toutes les instructions DDL spécifiées ont été
exécutées.
Vue supprimée.
Table supprimée.
Table supprimée.
Table supprimée.
Table supprimée.
Schéma créé.
SQL>
Une des instructions DDL spécifiées (CREATE VIEW) contient une erreur (nom de colonne incorrect ligne 18) et n’a pu
aboutir. L’autre instruction (CREATE TABLE) spécifiée dans le CREATE SCHEMA AUTHORIZATION a été annulée.
Table supprimée.
Vue supprimée.
SQL>
SQL> select * from LIGCDES ;
select * from LIGCDES
*
ERREUR à la ligne 1:
ORA-00942: Table ou vue inexistante
SQL>
c. Les objets Synonym
Un synonyme est le nom alternatif donné à un objet TABLE, VIEW, SEQUENCE, SNAPSHOT, PROCEDURE, FUNCTION
ou PACKAGE.
Les synonymes apportent plus de souplesse dans la gestion des noms d’objets :
● mise à disposition d’objets pour tous les utilisateurs sous le même nom,
● masquage du nom du SCHEMA auquel appartient l’objet,
● possibilité de référencer plusieurs fois un objet dans une requête,
● simplification dans l’écriture des requêtes.
Création
Syntaxe
PUBLIC place le synonyme dans le schéma PUBLIC, le rendant ainsi visible de tout utilisateur défini sur la base de
données (sans référence à un schéma). Sinon le synonyme reste local au SCHEMA de l’utilisateur propriétaire.
Les synonymes offrent la possibilité d’attribuer plusieurs noms à un même objet, ce qui va permettre une
simplification lors de l’écriture des requêtes, surtout lorsque la même table doit être utilisée plusieurs fois dans le
même ordre SELECT.
Les synonymes PUBLIC sont très utiles car ils offrent la possibilité à une application de travailler avec des tables
sans tenir compte du schéma sur lequel les objets ont été créés. Avec ce type d’élément, l’application cliente est
totalement indépendante de la structure de la base et du propriétaire des éléments.
Suppression
Syntaxe
Exemple
Jointure de la table NOMENCLATURE avec ellemême pour visualiser les articles composés :
6 ligne(s) selectionnée(s).
Synonyme créé.
SQL>select COMPOSE.REFART,COMPOSE.DESIGNATION,
2 NOMENCLATURE.NOMBRE,
3 NOMENCLATURE.DESIGNATION
4 from NOMENCLATURE,COMPOSE
5 where NOMENCLATURE.COMPOSANT=COMPOSE.REFART
6 order by COMPOSE.REFART;
d. Les objets Sequence
La création d’un objet SEQUENCE met à disposition de l’utilisateur un générateur de nombres.
Les séquences sont utilisées pour générer des numérotations automatiques, en particulier pour la création de
valeurs de clé primaire.
L’utilisation d’une SEQUENCE est plus souple et donne de meilleures performances que la gestion manuelle des
compteurs par l’intermédiaire d’une table.
Cependant l’utilisation d’une séquence ne garantit pas l’absence de "trous" dans la numérotation. La séquence est
un simple générateur de numéros et tous les numéros sont différents mais si des numéros sont demandés à une
séquence et ne sont pas utilisés par la suite, alors ces numéros sont perdus. La séquence est en effet un objet à
part entière et peut être utilisée par plusieurs tables.
Chaque valeur séquence s’exprime au maximum sur 28 chiffres significatifs.
Syntaxe
Paramètres
START WITH n
Valeur initiale.
INCREMENT BY n
Pas d’incrémentation. Il peut être positif ou négatif.
MINVALUE n/NOMINVALUE
Valeur limite minimum ou non.
MAXVALUE n/NOMAXVALUE
Valeur limite maximum ou non.
CYCLE/NOCYCLE
CACHE n/NOCACHE
Force l’anticipation de la génération des valeurs suivantes de la séquence en mémoire. A pour effet d’améliorer les
temps de réponse de la séquence.
ORDER/NOORDER
Garantit un ordre d’affectation des nombres dans l’ordre des demandes. Cette option ne présente d’intérêt que dans
le cas de l’utilisation de l’option PARALLEL OPTION en mode PARALLEL au niveau de l’instance Oracle.
L’utilisation se fait par l’intermédiaire des pseudoscolonnes dans les instructions de manipulation de données.
Pseudoscolonnes
nomseq.CURRVAL
Donne la valeur actuelle de la séquence. Cette pseudocolonne n’est pas valorisée par la création de la séquence ni
lors de l’ouverture d’une nouvelle session.
nomseq.NEXTVAL
Incrémente la séquence et retourne la nouvelle valeur de la séquence. Cette pseudocolonne doit être la première
référencée après la création de la séquence ou une ouverture de session.
SQL> create sequence C_NOCLI start with 1000 maxvalue 9999 nocycle;
Séquence créée.
1 ligne créée.
1 ligne créée.
2. Les requêtes complexes
a. Éléments de syntaxe
Les alias de colonne permettent de :
● Changer le nom de la colonne à l’affichage ou pour la table résultante.
● Donner un nom comportant des caractères spéciaux (espace par exemple).
Les alias de table définis dans les clauses FROM des instructions SELECT correspondent à des synonymes internes à
la requête. Ils permettent d’alléger l’écriture de l’instruction et de référencer dans des contextes différents la même
table dans une instruction DML complexe (avec sousrequête).
Syntaxe
Exemples
Affichage d’un nom de colonne comportant des espaces :
SQL>
Utilisation de la table d’origine dans une sousrequête. Alignement de la quantité en stock de chaque article à la valeur
maximum de la quantité en stock pour la famille (deux premiers caractères de la référence).
9 ligne(s) sélectionnée(s).
SQL>
Any
Compare, suivant l’opérateur donné (=,<>,<,<=,>,>=), les valeurs des colonnes spécifiées avec chacune des valeurs
de la liste. L’expression est vraie si au moins une des comparaisons est vraie. La liste de valeurs peut être une liste
de constantes littérales ou des valeurs retournées par une sousrequête.
La sousrequête ou la liste de valeurs doit retourner autant de valeurs que la liste d’expressions à comparer.
Exemple
Affichage des articles ayant le même prix que l’article ZZ01 :
SQL>
All
Compare, suivant l’opérateur donné (=,<>,<,<=,>,>=), les valeurs des colonnes spécifiées avec chacune des valeurs
de la liste. L’expression est vraie si toutes les comparaisons sont vraies. La liste de valeurs peut être une liste de
constantes littérales ou des valeurs retournées par une sousrequête.
Syntaxe
Exists
La condition est vraie si la sousrequête retourne au moins une ligne.
Syntaxe
Exemple
La liste des clients n’est affichée que si au moins une commande existe dans la table COMMANDES.
NOCLI NOMCLI
--------- ------------------------------
1000 DUPOND et DUPONT
1001 DURAND et DURANT
15 DUPONT S.A.
20 Etb LABICHE
35 DUBOIS Jean
36 BERNARD S.A.
138 DUBOIS Jean
152 LAROCHE
8 ligne(s) sélectionnée(s).
4 ligne(s) supprimée(s).
SQL>
Dans l’écriture d’une requête complexe, on distingue la requête externe de la requête interne, la sousrequête.
Les sousrequêtes peuvent être divisées en deux catégories : les sousrequêtes imbriquées et les sousrequêtes
corrélées.
Sousrequêtes imbriquées
Dans une sousrequête imbriquée il n’y a pas de lien explicite entre la requête interne et la requête externe. La
requête interne est exécutée une seule fois pour construire la liste de valeurs, avant l’exécution de la requête
externe (quel que soit le nombre de lignes ramenées par celleci).
Exemple
Liste des clients qui habitent dans la même ville que le client "DUBOIS Jean".
SQL>
Sousrequêtes corrélées
Dans une sousrequête corrélée, la condition spécifiée dans la clause WHERE de la requête interne fait référence à
une ou plusieurs colonnes de la requête externe. La requête interne est donc réexécutée pour chaque ligne
retournée par la requête externe.
Exemple
Liste des clients pour lesquels il n’existe pas de commande.
NOCLI NOMCLI
---------- ------------------------------
15 DUPONT S.A.
20 Etb LABICHE
35 DUBOIS Jean
36 Bernard S.A.
37 Ets LAROCHE
138 DUBOIS Jean
152 LAROCHE
7 ligne(s) sélectionnée(s).
SQL>
Différence entre les deux types de sousrequêtes
Lors de l’écriture des sousrequêtes, il est possible de choisir l’écriture de sousrequête imbriquée, qui favorise alors
l’utilisation de la clause IN, ou bien l’écriture de sousrequête corrélée, qui favorise l’utilisation de la clause EXISTS.
Pour savoir qu’elle est la solution à retenir en fonction des données à extraire, il faut se pencher un peu plus sur le
fonctionnement des clauses IN et EXISTS.
Dans le cadre d’utilisation de la clause IN (sousrequête imbriquée), il est possible de concevoir que la sousrequête
est évaluée comme une vue en ligne et qu’une jointure est faite sur la table de la requête principale avec les
Dans le cas de l’utilisation de la clause EXISTS, la sousrequête corrélée est exécutée pour chaque ligne issue de la
requête externe. Cette solution sera donc favorable si la table de la requête externe est relativement faible et qu’il
existe de bons index posés sur la table de la sousrequête sur les colonnes qui participent à la jointure.
L’exemple illustrant la sousrequête corrélée est intéressant par rapport à une sousrequête imbriquée si :
● le nombre de clients est restreint par rapport aux commandes ;
● l’extraction des différents numéros de clients à partir de la table des commandes représente une lourde
charge de travail.
Un index est posé sur la colonne NOCLI de la table des commandes afin d’accélérer les temps de jointure.
c. Les requêtes hiérarchiques
Il est parfois nécessaire d’interroger les données suivant un ordre hiérarchique bien précis. Pour cela Oracle met à
notre disposition des commandes pour extraire les données en utilisant un ordre. Ces commandes sont CONNECT BY
PRIOR et START WITH. Lors de l’exécution d’une telle requête, Oracle procède de la façon suivante :
● Oracle sélectionne la racine de l’arbre, ce sont les lignes qui satisfont la condition indiquée dans la clause
START WITH.
● Oracle sélectionne les enfants de chaque père. Tous doivent satisfaire la condition indiquée dans la clause
CONNECT BY.
● Tous les enfants sont sélectionnés les uns après les autres.
● Si la requête contient une clause WHERE, Oracle supprime de la hiérarchie toutes les lignes qui ne respectent
pas la clause WHERE.
Pour savoir à quel niveau de la hiérarchie on se situe, Oracle met à notre disposition la pseudocolonne LEVEL.
Exemple
Création de table EMPLOYES. Chaque employé peut dépendre d’un chef dont il connaît le numéro. Le chef d’un employé est
lui aussi un employé. On souhaite connaître l’organigramme de l’entreprise.
Table créée.
SQL>
La requête SQL permet de connaître l’organisation hiérarchique de l’entreprise :
8 ligne(s) sélectionnée(s).
SQL>
La fonction SYS_CONNECT_BY_PATH, qui n’est utilisable que dans les requêtes hiérarchiques permet de connaître le
chemin complet depuis le sommet de l’arbre. Cette fonction ne peut s’appliquer qu’aux colonnes de type caractère.
L’exemple cidessous montre l’utilisation de cette fonction dans une requête hiérarchique.
NOM
----------------------------------------------------------------------
/Ernest
/Ernest/Bernard
/Ernest/Bernard/Albert
/Ernest/Bernard/Coutard
/Ernest/Bernard/Hestor
/Ernest/Fergre
/Ernest/Fergre/Dionaux
/Ernest/Fergre/Grillet
8 ligne(s) sélectionnée(s).
SQL>
La fonction CONNECT_BY_ROOT permet de connaître, à partir d’un élément extrait d’une requête hiérarchique, les
informations concernant le sommet de la hiérarchie. Il est nécessaire de faire précéder le nom des colonnes pour
lesquelles on souhaite cette information par CONNECT_BY_ROOT.
Cette fonctionnalité est surtout intéressante lorsque l’on souhaite extraire d’une façon hiérarchique les données
avec une restriction sur certains critères.
Par exemple, si la table contient des règles d’assemblage de pièces, il est possible à l’aide du CONNECT_BY_ROOT de
connaître les éléments qui possèdent la pièce sur laquelle est faite la restriction.
Exemple
L’exemple cidessous permet facilement de connaître le "grand chef" de chaque employé.
L’extraction de données de façon hiérarchique est souvent faite par étape. Pour savoir si un élément est terminal ou
non, il faut effectuer une requête hiérarchique à partir de cet élément. Avec la fonction CONNECT_BY_ISLEAF qui
retourne 0 si l’élément n’est pas feuille et 1 sinon, il est tout de suite possible d’identifier les éléments qui possèdent
un détail.
Exemple
Dans l’exemple cidessous on est capable de faire la distinction entre les employés qui gèrent une équipe et ceux qui ne le
font pas.
d. Pivoter les données
Depuis la version 11, il est possible, très facilement, de faire pivoter les données d’un résultat pour obtenir un
affichage sous la forme d’un tableau croisé.
À titre d’exemple, considérons une table qui stocke les ventes détaillées par code pays, code produit et année :
Nous pouvons interroger cette table pour produire un rapport donnant les ventes cumulées par pays et par année :
ANNEE CO SUM(MONTANT)
---------- -- ------------
2006 FR 1254781
2006 IT 1004852
2007 FR 1435278
2007 IT 986354
2007 US 835789
2008 FR 1451245
2008 IT 1034572
2008 US 1236745
8 ligne(s) sélectionnée(s).
Pour afficher le résultat sous la forme d’un tableau croisé, il faut modifier l’écriture de la requête et utiliser la clause
PIVOT.
Exemple
Syntaxe simplifiée
La clause fonction_agrégat(expression) permet de spécifier la formule de calcul de la donnée qui va être affichée
dans le tableau croisé ; cette formule de calcul doit utiliser une fonction d’agrégat (SUM, AVG, COUNT, etc).
La clause FOR permet de spécifier la colonne du résultat d’origine dont les valeurs doivent être affichées en colonne,
et de lister les valeurs qui seront affichées. Ces valeurs doivent être connues au départ ; il n’est pas possible de les
définir dynamiquement. Dans la liste des valeurs, des alias peuvent être définis pour modifier le titre de la colonne.
Exemple
ANNEE FRANCEUSAITALIE
---------- ---------- ---------- ----------
Il existe une variante de syntaxe qui permet de produire le résultat sous la forme d’un document XML. Avec
cette variante, la liste des valeurs peut ne pas être connue au départ.
Il existe aussi une clause UNPIVOT qui permet de faire l’opération inverse : transformer un tableau croisé en tableau.
Supposons que nous disposions d’une table des ventes qui stocke les données sous la forme d’un tableau croisé
(assez étrange comme conception, j’en conviens) :
Pour afficher le résultat sous la forme d’un tableau, il faut modifier l’écriture de la requête et utiliser la clause
UNPIVOT.
Exemple
8 ligne(s) sélectionnée(s).
Syntaxe simplifiée
titre_colonne_cellule définit le titre de la colonne qui va afficher la donnée initialement présente dans la cellule du
tableau croisé.
La clause FOR permet d’indiquer quelles colonnes du tableau croisé d’origine doivent devenir des valeurs d’une
colonne dont le titre est donné par titre_colonne_pivot.
La clause INCLUDE NULLS permet d’inclure dans le résultat des lignes pour les valeurs NULL ; par défaut, ces lignes
sont exclues.
9 ligne(s) sélectionnée(s).
3. Verrouillage des tables
Lors des transactions concurrentes (accès aux mêmes données depuis des transactions différentes), il est nécessaire
de préserver la cohérence des données.
À un instant donné, une seule transaction est autorisée à modifier une donnée (une ligne). Les autres transactions
souhaitant modifier la même donnée peuvent être mises en attente (sérialisation des demandes) de la fin de la
transaction.
Pour permettre ce fonctionnement, Oracle gère simultanément un verrou au niveau de chaque ligne en cours de
modification et un verrou au niveau de la table. Le verrou posé au niveau de la ligne (verrou TX : Row exclusive) est un
verrou exclusif : si une transaction a pu poser ce verrou, aucune autre ne pourra le faire avant que le verrou ne soit
relâché par la transaction (COMMIT ou ROLLBACK).
Les verrous de table peuvent être posés automatiquement par Oracle au cours de l’exécution des instructions DML
INSERT, UPDATE, DELETE et PL/SQL SELECT ... FOR UPDATE ou explicitement par les utilisateurs à l’aide de l’instruction
LOCK TABLE.
Types de verrou
EXCLUSIVE (X)
La pose de ce type de verrou sur une table empêche toute autre transaction de poser explicitement un verrou sur
cette table et d’accéder à cette table en modification.
SHARE (S)
La pose de ce type de verrou sur une table empêche toute autre transaction de poser un verrou autre qu’un verrou
SHARE sur la table et d’y accéder en modification.
ROW SHARE (RS)
La pose de ce type de verrou sur une table permet l’accès concurrent à la table (modification de lignes différente dans
chacune des transactions) et empêche toute autre transaction de poser sur cette table un verrou exclusif. C’est un
verrou d’intention.
ROW EXCLUSIVE (RX)
La pose de ce verrou sur une table indique que des lignes y ont été modifiées par une instruction DML. Il empêche la
pose d’un verrou exclusif à partir d’une autre transaction.
SHARE ROW EXCLUSIVE (SRX)
Les instructions DML INSERT, UPDATE, DELETE posent automatiquement un verrou RX sur la table en cours de
modification. Une instruction SELECT ... FROM ... FOR UPDATE dans un bloc PL/SQL provoque la pose d’un verrou S sur
la table.
Lock
Syntaxe
Exemple
Session 1 : la transaction verrouille la table COMMANDES de façon exclusive.
Table(s) verrouillée(s).
SQL>
Session 2 : tentative de mise à jour d’une ligne de la table COMMANDES. L’instruction se met en attente du déverrouillage
de la table.
Session 1 : insertion d’une ligne et validation de la transaction.
1 ligne créée.
SQL> commit ;
Validation effectuée.
SQL>
Session 2 : l’instruction d’insertion est exécutée mais échoue car la même donnée vient d’être insérée dans l’autre session.
SQL>
4. Les commentaires
Afin de faciliter les opérations de mise à jour de la base, il est possible de poser des commentaires sur les tables et les
vues ainsi que sur chacune des colonnes qui composent ces tables et ces vues. La pose de commentaires est une
étape indispensable car elle permet de connaître très exactement la signification et le rôle de chaque élément de la
base de données. Tous ces commentaires sont stockés dans un dictionnaire de données et sont accessibles en
interrogeant certaines vues du dictionnaire.
Pour poser un commentaire sur les colonnes, il n’est pas indispensable d’avoir posé au préalable un
commentaire sur la table ou la vue.
Syntaxe
Exemple
Un commentaire est posé sur la table CLIENTS.
Un commentaire est ensuite posé sur la colonne adrcli pour expliquer les données contenues dans cette colonne :
Pour connaître les commentaires, il faut interroger le dictionnaire :
Les vues ALL_COL_COMMENTS et USER_ COL_COMMENTS contiennent les commentaires posés au niveau
colonne.
5. Informations sur les objets du schéma
Le dictionnaire de données possède de nombreuses vues qui donnent une information détaillée des différents
éléments présents dans le schéma.
Parmi les vues les plus couramment utilisées, on peut citer :
ALL_OBJECTS, USER_OBJECTS
ALL_CATALOG, USER_CATALOG
ALL_TABLES, USER_TABLES
ALL_TAB_COLUMNS, USER_TAB_COLUMNS
ALL_TAB_COMMENTS, USER_TAB_COMMENTS
ALL_COL_COMMENTS, USER_COL_COMMENTS
ALL_VIEWS, USER_VIEWS
ALL_INDEXES, USER_INDEXES
ALL_IND_COLUMNS, USER_IND_COLUMNS
ALL_SEQUENCES, USER_SEQUENCES
ALL_SYNONYMS, USER_SYNONYMS
ALL_DEPENDENCIES, USER_DEPENDENCIES
Exemple
La vue USER_TABLES est utilisée pour connaître toutes les tables de l’utilisateur courant.
6. Fonctionnalités spécifiques
NLS
Certaines fonctions doivent réagir différemment suivant le langage sélectionné au niveau du serveur Oracle. Au niveau
Oracle, tous ces critères sont fixés par les paramètres NLS (National Language Support). Ces paramètres ont une
incidence principalement sur l’affichage des données de type date et sur l’affichage des données de type numérique.
Toutes les fonctions SQL qui dépendent de NLS acceptent de prendre en charge un paramètre NLS spécifique. Ces
fonctions sont : TO_CHAR, TO_DATE, TO_NUMBER, NLS_UPPER, NLS_LOWER, NLS_INITCAP, NLSSORT.
Le principal intérêt de fixer le paramètre NLS au niveau de la fonction est de passer outre le choix réalisé au niveau de
la session.
Exemple
Utilisation de paramètre NLS dans une fonction. Pour comparer deux dates, l’exemple suivant transforme la date de
référence, qui est saisie sous forme de chaîne de caractères en donnée de type Date. Pour réaliser cette transformation, la
fonction TO_DATE est utilisée. En plus de la chaîne de caractères contenant la date, cette fonction accepte deux autres
paramètres : le format de la date et le paramètre de type NLS indiquant dans quelle langue la date a été saisie.
La liste des différents paramètres NLS disponibles sur les fonctions SQL :
Fonctions SQL Paramètres NLS
TO_DATE NLS_DATE_LANGUAGE
NLS_CALENDAR
TO_NUMBER NLS_NUMERIC_CHARACTERS
NLS_ISO_CURRENCY
TO_CHAR NLS_DATE_LANGUAGE
NLS_NUMERIC_CHARACTERS
NLS_CURRENCY
NLS_DUAL_CURRENCY
NLS_ISO_CURRENCY
NLS_CALENDAR
NLS_UPPER NLS_SORT
NLS_LOWER NLS_SORT
NLS_INITCAP NLS_SORT
Différents exemples d’utilisation des paramètres NLS sont illustrés dans l’exemple suivant :
TO_CHAR(datecde,’DD/MON/YYYY’,’NLS_DATE_LANGUAGE=FRENCH’)
TO_NUMBER(’15.999,80’,’9G999D99’,’NLS_NUMERIC_CHARACTERS=’’,.’’’)
TO_CHAR(prix,’9G999D99F’,’NLS_NUMERIC_CHARACTERS=’’,.’’
NLS_ISO_CURRENCY=Japan’)
NLS_UPPER(nomcli, ’NLS_SORT=SWISS’)
NLSSORT(nomcli,’NLS_SORT=GERMAN’)
Case
L’instruction CASE permet de mettre en place une condition d’instruction conditionnelle directement dans la requête
SELECT, sans faire appel à un bloc d’instructions procédurales.
L’intérêt principal de cette instruction est de faciliter la présentation et la mise en forme des résultats directement
dans les requêtes SELECT. L’instruction CASE permet également de limiter le nombre de fois où il est nécessaire de
faire appel à un bloc PL/SQL pour résoudre le problème.
L’instruction CASE est limitée à 128 choix. Pour pouvoir outrepasser cette limite, il est nécessaire d’imbriquer
les instructions les unes dans les autres.
Syntaxe
CASE expression
WHEN expression_comparaison1 THEN expression_retournée1
WHEN expression_comparaison2 THEN expression_retournée2
....
[ELSE expression_retournée]
END
CASE
WHEN condition1 THEN expression_retournée1
WHEN condition2 THEN expression_retournée2
....
[ELSE expression_retournée]
END
L’instruction ELSE est optionnelle et, dans le cas où cette condition n’est pas présente, la valeur retournée est NULL si
aucune instruction WHEN ... THEN n’est exécutée.
Exemple
L’exemple cidessous permet de connaître le libellé du département des clients à partir du code postal.
7 ligne(s) sélectionnée(s).
SQL>
Dans cet exemple, c’est la région qui est connue à partir du code postal du client.
7 ligne(s) sélectionnée(s).
SQL>
7. Les expressions régulières
Les expressions régulières représentent un outil puissant pour travailler avec les chaînes de caractères. Cette
fonctionnalité est déjà présente sur de nombreux langages de programmation et sous Unix.
Les requêtes d’extraction de données avec des critères très précis de sélection sur les données de type caractère
vont pouvoir être écrites plus facilement.
Pour pouvoir travailler avec les expressions régulières, Oracle propose un opérateur REGEXP_LIKE et quatre
fonctions : REGEXP_INSTR, REGEXP_SUBSTR, REGEXP_REPLACE et REGEXP_COUNT.
Les expressions régulières vont décrire à l’aide de métacaractères la structure que doit posséder la chaîne de
caractères avec laquelle on souhaite travailler.
Bien que les différents métacaractères soient présentés par la suite, il est préférable de travailler avec quelques
exemples d’expressions régulières afin de bien comprendre comment elles fonctionnent.
Les ancres
^ : marque le début de la ligne
$ : marque la fin de la ligne
Les quantifieurs
* : correspond à 0 ou plusieurs caractères.
? : correspond à 0 ou 1 caractère.
+ : correspond 1 ou plusieurs caractères.
{m} : correspond à m caractères exactement.
{m,} : correspond à au moins m caractères.
Il faut faire attention à la manipulation de ces métacaractères car ils ne possèdent pas forcément le même sens que
ceux utilisés avec l’opérateur LIKE.
Le caractère . permet de signaler l’existence de n’importe quel caractère dans la chaîne.
Par exemple, l’expression régulière a.l peut correspondre aux chaînes de caractères apl, agl, ... mais également table,
stable, allo. En effet dans l’expression régulière, seul est stipulé que les lettres a et l doivent être séparées par un
caractère exactement. En aucun cas il n’est dit que la chaîne de caractères doit commencer par la lettre a et se finir
par la lettre l. Si l’on souhaite un tel scénario, il faut utiliser les ancres afin de préciser le caractère qui marque le début
de la chaîne. L’expression régulière ^a.l précise que la chaîne de caractères recherchée doit obligatoirement
commencer par la lettre a, soit par exemple apl, agl, allo...
Par défaut, les caractères présents dans l’expression régulière ne doivent être présents qu’une seule fois dans la
chaîne de caractères. Ainsi l’expression régulière ^a.*e$ signifie que l’on recherche une chaîne commençant par la
lettre a et se terminant par la lettre e. Entre le premier et le dernier caractère il est possible d’avoir entre 0 et n
caractères. Les chaînes ae, ane, anémone, ... répondent à cette expression.
Afin de permettre la construction d’expressions encore plus complexes, Oracle supporte les classes de caractères
POSIX (Portable Operating system Interface). Grâce à cette classe de caractères, il va être possible d’écrire des
expressions régulières extrêmement précises afin de retrouver seulement l’information voulue.
Les classes de caractères POSIX sont citées dans le tableau cidessous :
[:alpha:]
caractère alphabétique.
[:lower:]
caractère alphabétique en minuscule.
[:upper:]
caractère alphabétique en majuscule.
[:digit:]
numéro.
[:alnum:]
caractère alpha numérique.
[:space:]
espace.
[:punct:]
caractère de ponctuation.
[:cntrl:]
caractère de contrôle non imprimable.
[:print:]
caractère imprimable.
Ces différentes classes de caractères permettent de couvrir l’ensemble des caractères présents dans la table ASCII.
Pour pouvoir utiliser les classes de caractères POSIX dans les expressions régulières, il est nécessaire de les
positionner entre des crochets [].
Par exemple, l’expression [[:upper:]] permet de rechercher une chaîne de caractères écrite uniquement en majuscules
alors que [[:lower:]]{5} correspond à des mots de 5 lettres en minuscules.
Pour affiner les recherches, il est possible de citer une liste de caractères que l’on souhaite voir apparaître à un
Par exemple ^A[[:lower::]] correspond aux chaînes Ane, Anneau, Arbre, Appel, .... Par contre l’expression ^A[^nop]
[[:lower:]] permet simplement d’extraire Arbre, Ami, Avant, ....
Le caractère permet de simplifier l’écriture des plages de valeur en citant simplement le premier et le dernier
caractères séparés par . Par exemple dans l’expression ^A[np][[:lower:]] permet d’identifier les chaînes suivantes
Ane, Anneau, Appel, ....
Par contre s’il est placé en premier caractère d’une liste, il signale que les caractères situés à sa suite ne peuvent pas
participer à la chaîne final.
Donc l’expression ^A[nop][[:lower:]] permet d’identifier Avant, Ami, Arbre....
REGEXP_LIKE
Cet opérateur permet l’utilisation des expressions régulières pour la recherche dans les clauses WHERE ou bien lors
de la construction des contraintes d’intégrité.
Syntaxe
REGEXP_LIKE(colonne, expression_regulière)
Exemple
Dans l’exemple suivant, on recherche les clients dont le nom commence par B suivi de caractères en minuscules.
Mais l’opérateur REGEXP_LIKE peut également être utilisé pour définir des contraintes d’intégrité bien précise.
Par exemple, si l’on souhaite que les deux premiers caractères d’une référence article soit toujours des caractères
alphabétiques en majuscules, il est possible d’ajouter la contrainte d’intégrité suivante à la table des articles :
REGEXP_REPLACE
La fonction REPLACE en SQL permet de substituer une chaîne de caractères par une autre. Mais l’utilisation de cette
fonction nécessite de connaître exactement la chaîne à remplacer, ce qui n’est pas toujours le cas. La fonction
REGEXP_REPLACE quant à elle se sert simplement d’une description de la chaîne à remplacer.
Syntaxe
REGEXP_REPLACE(chaîne, expression_regulière,
chaîne_de_remplacement)
Exemple
Par exemple lorsque l’on souhaite éliminer les espaces inutiles dans une chaîne de caractères, la seule certitude que l’on
possède est que s’il y a plus d’un espace (deux, trois ou plus) alors il est possible d’éliminer les espaces inutiles.
REGEXP_INSTR
Cette fonction, dont l’objectif est le même que INSTR, permet de localiser l’emplacement de départ d’une souschaîne à
l’intérieur d’une chaîne. L’avantage réside dans le fait qu’il n’est pas nécessaire de citer la souschaîne, mais il suffit de
la décrire à l’aide d’une expression régulière pour la localiser.
Syntaxe
REGEXP_INSTR(chaîne, expression_regulière)
Exemple
Dans l’exemple cidessous, on souhaite connaître la position de la souschaîne S.A. dans le nom des clients.
REGEXP_SUBSTR
Comme pour la fonction SUBSTR, l’objectif de REGEXP_SUBSTR est d’extraire une souschaîne à partir d’une chaîne de
caractères, mais en décrivant la souschaîne extraite à l’aide d’une expression régulière. Ceci permet d’extraire la
souschaîne sans connaître sa position exacte, ni même sa longueur.
Syntaxe
REGEXP_SUBSTR(chaine, expression_regulière)
Exemple :
Dans l’exemple suivant, les noms des clients qui commence par LA est extrait.
REGEXP_COUNT
REGEXP_COUNT retourne le nombre de fois où l’expression régulière est trouvée dans la chaîne. La fonction retourne
0 si l’expression régulière n’est pas trouvée.
Syntaxe
REGEXP_COUNT(chaîne, expression_régulière)
Exemple :
Compter le nombre de mots d’une phrase.
SQL> select
2 regexp_count(’il était une fois’,’[[:alnum:]]+’) nombre_mots
3 from dual;
NOMBRE_MOTS
-----------
4
L’outil principal pour l’utilisation du SQL et du PL/SQL est l’interface utilisateur SQL*Plus.
Ce programme permet aux utilisateurs finaux, aux développeurs et aux administrateurs les fonctionnalités suivantes :
● manipulation et exécution de commandes SQL et de blocs PL/SQL.
● mise en forme des résultats de requêtes.
● visualisation des structures des tables et copie de données interbase.
● commandes et opérations d’entrée/sortie (saisie, affichage, manipulation de variables).
SQL*Plus possède également ses propres ordres de programmation. Il faut veiller à ne pas confondre l’utilitaire
SQL*Plus et le langage SQL.
Avant la version 11, l’outil SQL*Plus se déclinait sous trois formes différentes :
● outil ligne de commande (sqlplus.exe) ;
● application graphique Windows (sqlplusw.exe) ;
● application Web (iSQL*Plus).
Depuis la version 11, seule la version ligne de commande subsiste.
1. Connexion et déconnexion
Pour pouvoir utiliser le SQL, il faut se connecter à la base de données, c’estàdire fournir un nom d’utilisateur,
éventuellement protégé par un mot de passe.
SQL*Plus permet, soit de se connecter automatiquement en passant le nom et le mot de passe en paramètres de la
ligne de commande du système d’exploitation, soit de demander le nom ou le mot de passe après le lancement.
On peut, en outre, changer de nom d’utilisateur en cours de session SQL*Plus en se reconnectant.
a. Lancement du programme
À partir du prompt du système d’exploitation ;
Syntaxe
sqlplus[[-S] [nomuser[/motpasse][@chaîne_de_connexion]]
-S
Mode silencieux.
nomuser
Nom de connexion à la base.
motpasse
Mot de passe de l’utilisateur.
Nom du service défini dans le fichier TNSNAMES.ORA à utiliser pour se connecter au serveur Oracle.
Les différents ordres permettant la configuration de SQL*Plus sont détaillés par la suite.
Si l’on souhaite retrouver toujours le même environnement de travail, il est possible de stocker ses préférences dans
le ficher login.sql. Le fichier login.sql du répertoire courant est exécuté à la première connexion à SQL*Plus.
Exemples
Lancement du programme avec passage en paramètres du nom de l’utilisateur (TOTO) et du mot de passe (PIZZA) :
$sqlplus toto/pizza
Connecté à :
...........
SQL>
Lancement du programme avec demande de connexion (le mot de passe est saisi en frappe aveugle) :
$sqlplus
username : toto
password :
Connecté à :
............
SQL>
b. Connexion après lancement
CONNECT
Syntaxe
CONNECT [nomuser[/motpasse]][@chaîne_de_connexion]]
Exemple
L’utilisateur courant veut se connecter sous le nom FLORIAN :
La chaîne de connexion n’est nécessaire que si l’on souhaite se connecter à un serveur Oracle qui n’est pas local. On
peut donc se passer de chaîne de connexion lorsque l’on exécute SQL*PLUS directement sur le serveur Oracle.
Connexion à une base distante depuis SQL*PLUS
c. Changement du mot de passe
Permet à l’utilisateur de changer son mot de passe dans l’environnement SQL*Plus.
PASSWORD
Syntaxe
PASSWORD [nomuser]
Exemple
Changement du mot de passe de l’utilisateur courant.
d. Déconnexion
Après déconnexion, l’utilisateur ne peut plus utiliser de commande SQL ou PL/SQL.
DISCONNECT
Syntaxe
DISCONNECT
Exemple
Déconnexion sans sortie de SQL*Plus :
SQL>DISCONNECT
Disconnected from .......
.......
SQL>
e. Sortie de SQL*Plus
La sortie du programme entraîne la déconnexion à la base.
Syntaxe
SUCCESS/FAILURE/WARNING/n/ variable/:variable_liée
Permet de communiquer au système d’exploitation un code de retour sur l’exécution de la session.
COMMIT/ROLLBACK
Valide ou annule la transaction en cours au moment de la fin de session (COMMIT par défaut).
Exemple
Sortie de SQL*Plus et retour au système d’exploitation ($ : prompt UNIX).
SQL> EXIT
$.
2. Exécution des instructions
Après la connexion, l’utilisateur peut utiliser SQL*Plus pour saisir des commandes SQL, des blocs PL/SQL ou des
commandes SQL*Plus, à partir du prompt.
Les commandes SQL et PL/SQL peuvent être saisies sur plusieurs lignes (on marque une fin de ligne par la touche
[Entrée]), le caractère de fin de commande étant le pointvirgule (;). Pour améliorer la lisibilité on peut insérer dans la
syntaxe autant d’espaces ou de tabulations qu’on le souhaite. Il n’y a pas de distinction entre majuscules et
minuscules (sauf utilisation de guillemets).
Exemple
Création de lignes dans la table CLIENTS :
Les commandes SQL*Plus ne nécessitent pas de caractère de fin de commande, la marque de fin de ligne ([Entrée])
suffit. Si une commande doit être saisie sur plusieurs lignes, il faut utiliser le caractère de césure de ligne (tiret ()).
Exemple
Déclaration de format de colonne :
a. Gestion du buffer
La dernière instruction SQL est stockée en mémoire (buffer).
Ce buffer peut être réutilisé dans plusieurs cas :
● réexécution de la dernière commande SQL ou du dernier bloc PL/SQL.
● visualisation de la dernière commande.
● modification de la dernière commande.
● sauvegarde dans un fichier du buffer.
La réexécution du buffer se fait par la commande RUN ou /.
LIST
Visualisation du buffer.
La ligne courante est indiquée par une astérisque (*). Il est possible de changer la ligne courante en ne listant
qu’une seule ligne (on précise son numéro). La ligne listée devient alors la nouvelle ligne courante.
Syntaxe
n, m : numéro de ligne
* : ligne courante
LAST : dernière ligne
Il est également possible de lister une seule ligne (qui devient alors la ligne courante) en tapant directement
le numéro de la ligne.
Exemple
Saisie d’une commande SQL, visualisation du buffer, puis exécution :
INPUT
Ajout de ligne au buffer après la ligne courante.
Syntaxe
I[NPUT] [texte]
Exemple
Ajout d’une ligne à la dernière commande :
SQL> select *
2 from clients
3 where nocli>15
4
SQL> i
4 order by nomcli
5
SQL> l
1 select *
2 from clients
3 where nocli>15
4* order by nomcli
SQL>
APPEND
Ajout à la fin de la ligne courante.
Syntaxe
A[PPEND] texte
Exemple
Ajout de texte à la fin de la ligne 2 :
SQL> l
1 select * from CLIENT
2 where NOCLI>15
3* order by NOM
SQL> 2
2* where NOCLI>15
SQL> A and NOCLI<20
2* where NOCLI>11 and NOCLI<20
SQL>
CHANGE
Modification de la ligne courante.
Si le nouveau texte est omis, il y a suppression de l’ancien texte.
Exemple
Modification de la première ligne :
SQL> l
1 select * from clients
2* order by NOCLI
SQL>1
1* select * from clients
SQL>C/clients/COMMANDES
1* select * from COMMANDES
SQL>
DEL
Suppression d’une ou de plusieurs lignes du buffer.
Syntaxe
n, m : numéro de ligne
* : ligne courante
LAST : dernière ligne
Si la commande DEL est exécutée sans paramètres alors la ligne courante est supprimée.
Si la ligne courante est supprimée, alors c’est la ligne suivante (si elle existe) qui devient la nouvelle ligne
courante.
Exemple
Suppression de la dernière ligne du buffer :
SQL> l
1 select * from clients
2 where NOCLI>10
3* order by NOM
SQL> del
SQL> l
1 select * from clients
2* where NOCLI>10
SQL>
SAVE
Sauvegarde du buffer dans un fichier.
Syntaxe
Le fichier créé prend automatiquement l’extension .sql si aucune autre extension n’est précisée.
CREATE
(Option par défaut) crée un nouveau fichier.
REPLACE
Remplace le contenu d’un fichier existant.
Ajoute le buffer à la fin d’un fichier existant.
GET
Chargement du buffer à partir d’un fichier.
Syntaxe
LIST
(Option par défaut) liste le buffer.
NOLIST
Supprime l’affichage.
b. Utilisation de scripts
Il est possible de stocker des commandes SQL ou SQL*Plus dans des fichiers de texte soit par SAVE, soit par
l’éditeur système, puis d’exécuter ces scripts par SQL*Plus. Ces fichiers de commandes sont reconnus avec
l’extension par défaut .sql, ils peuvent contenir des commentaires.
EDIT
Appel de l’éditeur standard du système d’exploitation.
Syntaxe
[ED]IT [nomfic]
L’éditeur appelé est l’éditeur système sauf si la variable _EDITOR est valorisée (sous UNIX def _editor = vi, sous NT
def _editor=notepad.exe).
Edit charge par défaut le fichier avec l’extension .sql. Si aucun nom de fichier n’est spécifié, Edit crée un fichier
AFIEDT.BUF et recharge le buffer avec le contenu du fichier au retour dans SQL*Plus.
REM
Commentaires.
Syntaxe
REM[ARK] texte
Le texte sera ignoré à l’exécution.
Les commentaires peuvent aussi être indiqués par :
--
Le reste de la ligne situé après est ignoré par SQL*Plus.
/*... */
Le texte situé entre ces deux séparateurs est ignoré par SQL*Plus. Le commentaire peut comporter plusieurs lignes.
START,@,@@
Exécution des commandes contenues dans le fichier.
Syntaxe
Par défaut, l’extension .sql est prise pour le fichier.
COPY
Il est possible de copier des données d’une table à une autre table située sur une base de données locale ou non.
Pour cela on utilise la commande SQL*Plus COPY et les clauses FROM et TO pour préciser la source et la destination
des données. Les données à copier sont issues d’une requête SELECT.
Syntaxe
FROM base
Permet de préciser le schéma qui contient les données à copier. Si la clause FROM est omise, alors l’origine des
données est le schéma auquel SQL*Plus est connecté.
TO base
Permet de préciser le schéma de destination des données. Si la clause TO est omise, alors la destination des
données est le schéma auquel SQL*Plus est connecté.
base
Sous ce terme sont regroupés le nom de l’utilisateur, son mot de passe et la chaîne de connexion pour accéder à
une base de données distante.
APPEND
Les données issues de la requête sont insérées dans la table de destination. Si cette dernière n’existe pas, alors la
table est créée avant l’insertion des données.
CREATE
Les données issues de la requête sont insérées dans la table de destination après la création de cette dernière. Si
la table de destination était déjà présente avant l’exécution de la commande COPY, alors une erreur est retournée.
INSERT
Les données issues de la requête sont insérées dans la table de destination. Si la table de destination n’existe pas,
alors COPY retourne une erreur.
REPLACE
Les données issues de la requête remplacent celles de la table de destination. Si la table de destination n’existe
pas, alors elle est créée par la commande COPY.
Exemple
La table DEPT de l’utilisateur SCOTT va être copiée sous le schéma de l’utilisateur LIVRE. Les deux schémas se situent sur
une base de données distante.
3. Gestion de l’environnement SQL*Plus
SQL*Plus permet de gérer directement (sans passer par le SQL) certaines fonctionnalités de la base, comme la
visualisation des structures d’objet ou la copie de données d’une base à une autre. Il est également possible de
personnaliser l’utilisation de SQL*Plus en modifiant des paramètres agissant sur le fonctionnement des commandes,
sur l’affichage, ou sur le résultat des commandes.
DESCRIBE
Description de structure de table, vue, synonyme ou code stocké.
Syntaxe
DESC[RIBE] objet
SPOOL
Redirection des sorties.
Syntaxe
SPO[OL] {nomfic/OFF/OUT}
nomfic
Nom du fichier recevant les sorties (extension .lst par defaut).
OFF
Fermeture du fichier.
OUT
Fermeture du fichier et sortie sur l’imprimante.
SHOW
Visualisation de l’environnement.
Syntaxe
SHO[W] {ALL/paramètre}
SET
Paramètres d’environnement.
Syntaxe
La valeur par défaut des paramètres est la première des valeurs possibles indiquées :
Validation automatique.
CMDSEP {;/OFF/ON/c}
Séparateur de commandes multilignes.
FEEDBACK {6/n/OFF/ON}
Affichage du nombre d’enregistrements selectionnés à partir de n.
LONG {80/n}
Format maximum des colonnes de type LONG.
NULL {texte}
Représentation des valeurs NULL.
PAUSE {OFF/ON/texte}
Activation de la pause en fin de page.
SPACE {1/n}
Nombre de caractères séparant les colonnes à l’affichage.
SQLCASE {MIXED/LOWER/UPPER}
Conversion en majuscules ou minuscules des commandes avant exécution.
SQLCONTINUE {>/texte}
Prompt de la énième ligne.
SQLNUMBER {ON/OFF}
Numérotation du prompt de énième ligne.
SQLPROMPT {SQL/texte}
Prompt de la première ligne.
SQLTERMINATOR {;/c/OFF/ON}
Caractère de fin de commande.
ECHO {OFF/ON}
Affichage des commandes d’un script à l’exécution.
TERMOUT {ON/OFF}
Affichage du résultat des commandes d’un script.
HELP
Accès au système d’aide (s’il a été installé).
Syntaxe
HELP [commande]
Syntaxe
Avec certains systèmes d’exploitation, il est possible d’utiliser un caractère générique pour lancer une
commande système depuis SQL*Plus. Comme ce caractère dépend du système, il faut consulter la
documentation Oracle relative à la plateforme d’installation pour connaître ce caractère.
1. Gestion des variables
Il est possible de gérer deux sortes de variables :
● les variables utilisateur, utilisées par SQL*Plus ou pour de la substitution de texte dans des commandes SQL
et SQL*Plus avant leur exécution.
● les variables de lien utilisées en interface avec le PL/SQL.
DEFINE
Création d’une variable utilisateur.
Syntaxe
Sans paramètre, DEFINE permet de visualiser les variables existantes.
Les variables créées sont obligatoirement de type caractère.
Certaines variables ont des noms et des utilisations réservées :
_EDITOR
Éditeur appelé par EDIT.
_O_VERSION
Version ORACLE.
_O_RELEASE
Numéro de "release" ORACLE.
_CONNECT_IDENTIFIER
Identifiant utilisé pour la connexion.
_DATE
Date courante.
On peut définir 1024 variables au maximum.
UNDEFINE
Suppression d’une variable utilisateur.
Syntaxe
UNDEF[INE] variable
Exemple
Création des variables x et _editor, visualisation des variables, suppression de x.
ACCEPT
Saisie d’une variable utilisateur.
Si la variable n’a pas été définie, elle est créée.
Syntaxe
NUM/CHAR
Caractères autorisés pour la valeur de la variable (chiffres uniquement ou alphanumérique). CHAR par défaut.
PROMPT texte
Affichage du texte avant la saisie.
HIDE
Frappe aveugle.
Exemple
Saisie des variables V_code et V_nom :
&nom
Utilisation d’une variable de substitution.
Syntaxe
&variable
Si la variable n’existe pas, une saisie est demandée.
Exemple
Saisie de variables et utilisation dans une commande SQL :
Permet en plus de créer la variable.
Syntaxe
&&variable
Exemple
Lorsque la requête est réexécutée, la valeur de la variable n’est pas redemandée.
SQL> run
1* select * from &&NomTab
ancien 1: select * from &&NomTab
nouveau 1: select * from LIGCDES
SQL>
VARIABLE
Création d’une variable pour utilisation dans un bloc PL/SQL.
Syntaxe
Sans paramètre, VARIABLE affiche les caractéristiques des variables existantes.
Une variable PL/SQL ne peut être valorisée que dans un bloc PL/SQL par des instructions spécifiques au PL/SQL, elle
est considérée par le PL/SQL comme une variable de l’hôte (préfixée de :).
PRINT
Affichage du contenu de la variable PL/SQL.
Syntaxe
PRINT variable
Exemple
NCLI
----------
7
SQL>
Le résultat des requêtes peut être mis en forme de manière simple en utilisant des commandes SQL*Plus.
Ces commandes sont généralement des déclarations qui doivent être faites avant les instructions SELECT et qui
doivent être annulées ou désactivées après la requête.
a. Contrôle du déroulement des scripts
PAUSE
Définition d’une suspension d’exécution.
Syntaxe
PAUSE [texte]
PROMPT
Affichage de texte.
Syntaxe
PROMPT [texte]
b. Entête et pied de page
Déclaration ou annulation d’un entête : TTITLE.
Déclaration ou annulation d’un pied de page : BTITLE
BTITLE, TTITLE
Syntaxe
Les différentes options sont :
COL n
Place le texte en colonne n.
SKIP n
Saute n lignes.
TAB n
Saute n colonnes.
LEFT/CENTER/RIGHT
Alignement.
BOLD
Caractère gras.
FORMAT
Format d’affichage composé de :
9 remplace un chiffre (ex. : format ’9999’ pour 4 chiffres).
$ est le préfixe du signe $.
B remplace les zéros non significatifs par des espaces.
MI/PR : MI affiche après une valeur négative, PR affiche les valeurs négatives entre crochets.
, insère une virgule.
. positionne la marque décimale (ex. : ’999.99’ pour 3 entiers 2 décimales).
V multiplie par 10 fois le nombre de décimales.
EEEE est une notation scientifique.
DATE est le format date.
An permet un affichage sur n caractères.
Les variables prédéfinies :
SQL.PNO
Page courante.
SQL.LNO
Ligne courante.
SQL.RELEASE
Numéro de release ORACLE.
SQL.SQLCODE
Dernier code erreur.
SQL.USER
Utilisateur courant.
c. Rupture
BREAK
Déclaration d’action à effectuer lors d’un changement de valeur de la colonne.
Syntaxe
BREAK [ON{colonne/expression/ROW/REPORT}
[{SKIP{n/PAGE}/DUPLICATES}]...]
d. Format de colonne
COLUMN
Déclaration des attributs des colonnes sélectionnées.
Syntaxe
Les différentes options sont :
Nom alternatif.
LIKE alias
Copie les attributs de l’alias.
CLEAR
Réinitialise les attributs.
FOLD_AFTER
Insère un retour chariot après la colonne.
FOLD_BEFORE
Insère un retour chariot avant la colonne.
FORMAT format
Format de la valeur affichée.
HEADING texte
Entête de colonne.
JUSTIFY{LEFT/CENTER/RIGHT}
Justification.
NEWLINE
Idem à FOLD_BEFORE.
NEW_VALUE variable
Place la valeur de la colonne dans la variable pour l’afficher dans l’entête de page.
OLD_VALUE variable
Idem à NEW_VALUE pour le pied de page.
NULL c
Texte pour les valeurs nulles.
NOPRINT/PRINT
Affichage ou non de la colonne.
WRAPPED/WORD_WRAPPED/TRUNCATED
Césure des lignes trop longues.
OFF
Désactivation de la définition.
ON
e. Calcul statistique
COMPUTE
Déclaration d’un calcul à effectuer au changement de valeur de l’expression (qui doit avoir été déclarée par un
BREAK).
Syntaxe
Les fonctions qu’il est possible d’utiliser sont :
AVG
Moyenne des valeurs non nulles.
COUNT
Dénombrement des valeurs non nulles.
MAXIMUM
Valeur maxi.
MINIMUM
Valeur mini.
NUMBER
Nombre de lignes.
STD
Écarttype.
SUM
Somme des valeurs.
VARIANCE
Variance.
f. Annulation des déclarations
CLEAR
Syntaxe
CLEAR {BREAKS/COLUMNS/COMPUTES/TIMING/BUFFER/SQL/SCREEN}
3. Environnement et traitement des erreurs
Un certain nombre de paramètres d’environnement permettent de gérer le fonctionnement des commandes de mise
en page. Ces paramètres sont généralement valorisés en début de script et annulés en fin de script.
a. Statistiques de temps
Syntaxe
b. Traitement des erreurs
En cas d’erreurs soit du système d’exploitation, soit du SQL, SQL*Plus les ignore, ce qui peut être gênant dans des
enchaînements de commandes ou pour l’intégrité des données.
La déclaration WHENEVER permet de prévenir ces erreurs.
WHENEVER
Syntaxe
EXIT
Sort de SQL*Plus en envoyant le code erreur spécifié.
CONTINUE
Ne sort pas de SQL*Plus.
COMMIT ou ROLLBACK
Force une validation ou une annulation avant de sortir ou de continuer.
NONE
Ne fait rien avant de sortir ou de continuer.
SET ERRORLOGGING
Syntaxe simplifiée
Active ou désactive l’enregistrement dans une table des erreurs qui surviennent dans SQL*Plus.
Par défaut, les erreurs sont enregistrées dans une table nommée SPERRORLOG ; si cette table n’existe pas, elle est
créée automatiquement.
TRUNCATE
Vide la table lors de l’activation de l’enregistrement.
IDENTIFIER
Chaîne de caractères utilisée pour identifier les erreurs.
c. Paramètres d’environnement
SET
Paramètres liés à l’affichage.
Syntaxe
caractère utilisé pour les substitutions de variables.
EMBEDDED {OFF/ON}
chaque rapport débute sur une nouvelle page.
HEADSEP {|/c/ON/OFF}
caractère définissant un entête de colonne multiligne.
LINESIZE {80/n}
nombre de caractères par ligne.
NEWPAGE {1/n/NONE}
nombre de lignes entre le début de page et l’entête défini.
NUMFORMAT {format}
format par défaut des numériques.
NUMWIDTH {10/n}
taille par défaut des numériques.
PAGESIZE {14/n}
nombre de lignes entre l’entête et le bas de page.
SCAN {ON/OFF}
contrôle la présence des variables de substitution.
SHOWMODE {ON/OFF}
affichage des valeurs des variables en cas de changement.
TAB {OFF/ON}
utilisation des tabulations.
TIME {OFF/ON}
affichage de l’heure avant chaque commande.
TIMING {OFF/ON}
affichage des statistiques de temps.
TRIMOUT {ON/OFF}
suppression des espaces en fin de ligne.
UNDERLINE {/c/ON/OFF}
caractère de soulignement.
VERIFY {ON/OFF}
liste la commande avant son exécution (en cas de substitution de variable).
césure des lignes.
La commande SET possède de nombreuses autres options mais seules les plus courantes sont documentées
dans cet ouvrage.
Exemple
Script de mise en page, extraction et sauvegarde dans un fichier (confcde.lis) d’une confirmation de commande dont le
numéro est saisi par l’utilisateur.
spool confcde.lis
rem Extraction
select COMMANDES.NOCDE,NOMCLIENT,LIGNESCDE.REFART,DESIGNATION,
PRIXUNITHT,QTECDE,PRIXUNITHT*QTECDE "Mt"
from COMMANDES,LIGNESCDE,CLIENTS,ARTICLES
where COMMANDES.NOCDE = &VCDE
and COMMANDES.NOCLIENT = CLIENTS.NOCLIENT
and COMMANDES.NOCDE = LIGNESCDE.NOCDE
and LIGNESCDE.REFART = ARTICLES.REFART
/
spool out
ttitle off
btitle off
clear breaks
clear columns
clear compute
set pagesize 14
set newpage 1
Résultat du script précédent si N° de commande saisi est 1210 :
Confirmation de commande
Numero : 1210
Client : DUPONT S.A.
Reference
article Désignation Prix H.T. Qté cde. Mt
---------- ----------------- ----------- --------- -------
AB10 Tapis de Chine 1500 3 4500
CD50 Chaîne HIFI 735,4 4 2941,6
-------
7441,6
Page 1
4. Création d’un rapport au format HTML
SQL*Plus offre la possibilité de créer un rapport au format HTML en utilisant les commandes SET MARKUP et SPOOL.
Les informations du rapport sont insérées à l’intérieur de la balise HTML <PRE>, et donc l’affichage au sein de
l’explorateur Internet est exactement le même que celui perçu dans SQL*Plus.
Syntaxe
Les choix par défaut des options sont soulignés.
La commande SET MARKUP permet à SQL*Plus de générer un résultat au format HTML et non plus au simple format
texte. L’intérêt de fournir directement les données au format HTML n’est plus à démontrer car ce format permet une
présentation simple à mettre en place et soignée tout en restant indépendante de l’outil utilisé pour visualiser le
résultat.
Les différents paramètres de cette commande sont :
HTML
(OFF par défaut) Positionner à ON la valeur de cette option permet d’activer la génération des résultats au format
HTML.
HEAD
Permet de personnaliser l’entête de la page HTML comme par exemple le fait de définir un titre à l’aide des balises
<TITLE> et </TITLE>. C’est également à cet endroit que l’on pourra définir les styles à appliquer aux différentes
balises.
BODY
L’option BODY permet de définir les attributs de la balise BODY. Par défaut aucun attribut n’est sélectionné mais il est
toujours possible de le faire par cette option.
TABLE
Permet de spécifier les attributs du tableau. Par défaut, le tableau est défini comme possédant une largeur de 90%
(WIDTH=’90%’) et la largeur de la bordure est fixée à 1 (border=’1’).
ENTMAP
(ON par défaut) Positionner à OFF la valeur de cette option permet d’interpréter les caractères HTML correctement, ce
qui peut être le cas pour <, >," et &. Avec cette précaution, ces caractères ne sont pas remplacés par leur entité
SPOOL
(OFF par défaut) Positionner à ON la valeur de cette option permet d’ajouter les balises <HTML> et <BODY> ainsi que
les balises fermant correspondant en début et fin de fichier. Ce paramètre n’est en aucun cas équivalent à la
commande SPOOL qui permet de rediriger les informations affichées à l’écran vers un fichier.
PREFORMAT
(OFF par défaut) indique à SQL*Plus que les résultats sont présentés sous forme de tableau. Positionner à ON la
valeur de cette option permet de préciser les informations indiquées après une balise <PRE>.
Afin de présenter au mieux le script SQL*Plus qui contient la commande SET MARKUP, il est fortement
recommandé de saisir cette commande sur plusieurs lignes en prenant soin de ne pas oublier le caractère de
continuation () des instructions SQL*Plus.
Le script cidessous illustre comment il est possible de produire un résultat au format HTML depuis SQL*Plus.
L’exécution de ce script donne le résultat suivant :
1. Lancer SQL Developer
Oracle SQL Developer est une application graphique permettant d’exécuter des requêtes ou des scripts SQL, de gérer
les objets d’une base de données (tables, vues, etc.) et de développer et mettre au point des programmes PL/SQL.
Oracle SQL Developer est gratuit et peut être téléchargé directement sur le site OTN (Oracle Technology Network). La
page d’accueil d’Oracle SQL Developer se trouve à l’adresse suivante :
http://www.oracle.com/technology/products/database/sql_developer/index.html. Vous trouverez notamment à cette
adresse la documentation et des tutoriaux.
Depuis la version 11, Oracle SQL Developer est installé par défaut avec le serveur Oracle et le client Oracle.
Sur plateforme Windows, Oracle SQL Developer peut être lancé par le menu Démarrer Programmes Oracle
nom_oracle_home Développement d’applications SQL Developer.
Sur plateforme Unix ou Linux, Oracle SQL Developer peut être lancé à l’aide du shell script
$ORACLE_HOME/sqldeveloper/sqldeveloper.sh ($ORACLE_HOME désigne le répertoire de l’installation d’Oracle).
L’application nécessite un environnement graphique.
Sur plateforme Windows, lors du premier lancement, il est possible que l’outil demande le chemin de l’application
java.exe. Vous pouvez utiliser celle fournie par Oracle : %ORACLE_HOME%\jdk\bin\java.exe (%ORACLE_HOME% désigne le
répertoire de l’installation d’Oracle).
La fenêtre principale d’Oracle SQL Developer a l’allure suivante :
Dans la partie gauche de la fenêtre, une structure arborescente permet de naviguer dans les objets d’une ou de
plusieurs bases de données. Dans la partie droite de la fenêtre, la zone de travail permet d’éditer et d’exécuter des
requêtes SQL et de visualiser le résultat.
Dans l’ensemble, cet outil est très convivial et son apprentissage est aisé. Dans ce chapitre, nous ferons une
présentation rapide de son utilisation ; pour plus d’informations, vous pouvez consulter la documentation "Oracle®
Database SQL Developer User’s Guide".
2. Créer une nouvelle connexion
Dans la boîte de dialogue qui s’affiche, vous devez saisir les informations suivantes :
Connection Name
Nom de la connexion.
Username
Compte à utiliser pour la connexion.
Password
Mot de passe du compte à utiliser pour la connexion.
Save Password
Si la case est cochée, le mot de passe est enregistré et ne sera pas demandé lors de l’ouverture de la connexion.
Hostname
Nom du serveur.
SID
Nom de l’instance.
Le bouton Test permet de tester la connexion. Le bouton Connect permet d’enregistrer la nouvelle connexion et de se
connecter.
3. Saisir des requêtes SQL
Pour ouvrir des zones de travail SQL supplémentaires, vous pouvez cliquer sur le bouton dans la barre d’outils
(ou choisir le nom d’une connexion dans la liste déroulante associée à ce bouton), ou faire un clic droit sur le nom
d’une connexion dans le panneau des connexions et sélectionner le menu Open SQL Worksheet.
Vous pouvez maintenant saisir la requête souhaitée dans la zone de saisie puis cliquer sur le bouton ou
appuyer sur la touche [F9] ; le résultat s’affiche dans l’onglet Results, comme dans une feuille Excel :
Une ou plusieurs requêtes peuvent aussi être exécutées sous la forme d’un script en cliquant sur le bouton ou
en appuyant sur la touche [F5] ; le résultat s’affiche dans l’onglet Script Output, comme dans SQL*Plus :
Un script SQL existant peut aussi être ouvert dans SQL Developer en cliquant sur le bouton puis en
sélectionnant le fichier dans la boîte de dialogue qui vous est proposée. Le script est ouvert dans une nouvelle zone
de travail :
Vous pouvez sélectionner une connexion pour cette nouvelle zone de travail à l’aide de la liste déroulante présentée
précédemment.
Une fois ouvert, le script peut être modifié puis exécuté (bouton ou touche [F5]) ; lors de la première exécution,
si aucune connexion n’a été sélectionnée au préalable, une boîte de dialogue s’affiche pour en choisir une.
Vous pouvez sauvegarder le script modifié en cliquant sur le bouton .
Oracle SQL Developer supporte un grand nombre de commandes SQL*Plus.
4. Mettre à jour les données
La zone de travail SQL présentée précédemment peut être utilisée pour saisir et exécuter des requêtes de mise à jour
(INSERT, UPDATE, DELETE). Dans ce cas, vous devez utiliser le bouton pour enregistrer définitivement les
modifications dans la base (COMMIT). En cas de besoin, pour annuler les modifications en cours (ROLLBACK), vous
pouvez cliquer sur le bouton .
Pour mettre à jour les données, vous pouvez aussi utiliser l’éditeur de données de la table.
Les données peuvent être modifiées directement dans la grille. Vous disposez aussi de plusieurs boutons pour agir
sur les données :
Insérer une nouvelle ligne.
Supprimer la ligne courante.
Enregistrer définitivement les modifications dans la base.
Annuler les modifications.
Dans la première colonne, le numéro des lignes modifiées est précédé d’un symbole : + pour une ligne insérée, pour
une ligne supprimée et * pour une ligne modifiée. Exemple :
5. Travailler avec les objets d’un schéma
Dans le panneau des connexions, vous pouvez naviguer très facilement dans les différents types d’objets d’un schéma
et visualiser leur définition.
Pour créer un nouvel objet, il faut sélectionner le dossier correspondant au type d’objet souhaité (table, vue, etc.),
faire un clic droit, puis sélectionner le menu New…. Une boîte de dialogue spécifique au type d’objet sélectionné est
alors affichée.
Exemple pour une table
Pour modifier la définition d’un objet, il suffit de le sélectionner dans le panneau des connexions, de faire un clic droit
et de sélectionner le menu Edit…. Une boîte de dialogue spécifique au type d’objet sélectionné est alors affichée.
Exemple pour une table
Cette boîte de dialogue permet de modifier les différentes caractéristiques de l’objet sélectionné.
D’une manière générale, en faisant un clic droit sur un objet, un menu contextuel s’affiche et offre différentes
possibilités d’action sur l’objet.
Exemple pour une table
6. Exporter des données
Les données affichées dans les différentes grilles d’Oracle SQL Developer peuvent être très facilement exportées sous
différents formats (CSV, XML, HTML, etc.).
Pour cela, il suffit de faire un clic droit dans la grille et de sélectionner un des sousmenus du menu Export Data :
Une boîte de dialogue est ensuite affichée afin de préciser notamment le nom du fichier :
7. Exporter des définitions
Oracle SQL Developer offre la possibilité d’exporter la définition (et les données) de tout ou partie des objets d’un
schéma.
Pour cela, il faut sélectionner le menu Tools Export DDL (and Data). Une boîte de dialogue Export s’affiche :
Cette boîte de dialogue permet de définir le fichier de destination et la connexion à utiliser, et de sélectionner les
différents types d’objets à exporter et les options de l’export.
L’onglet Filter Objects permet de définir des filtres sur les objets à exporter (basés sur le nom et le type de l’objet).
L’onglet Filter Data permet de définir des filtres sur les données à exporter.
Pour lancer l’export, il suffit de cliquer sur le bouton Appliquer.
1. Qu’estce que le PL/SQL ?
Le PL/SQL est le langage procédural d’ORACLE. Il constitue une extension au SQL qui est un langage ensembliste.
L’intérêt du PL/SQL est de pouvoir mélanger la puissance des instructions SQL avec la souplesse d’un langage
procédural dans un même traitement.
Ces traitements peuvent être exécutés, soit directement par les outils ORACLE (blocs anonymes), soit à partir
d’objets de la base (procédures stockées et PACKAGES).
Les avantages du PL/SQL sont multiples :
● Intégration du SQL : les instructions du DML, du transaction control et les fonctions SQL peuvent être utilisées
avec pratiquement la même syntaxe.
● Traitements procéduraux : la gestion des variables et les structures de contrôle (test, boucles) accroissent les
possibilités de gestion des données.
● Fonctionnalités supplémentaires : la gestion des curseurs et le traitement des erreurs offrent de nouvelles
possibilités de traitements.
● Amélioration des performances : plusieurs instructions sont regroupées dans une unité (bloc) qui ne génèrera
qu’un "accès" à la base (à la place d’un accès par instruction).
● Incorporation aux produits ORACLE : les blocs ou procédures PL/SQL sont compilés et exécutés par le
"moteur" PL/SQL. Ce moteur est directement intégré au moteur de la base de données ainsi qu’à certains
outils Oracle : Oracle*Forms, Oracle*Report.
2. Instructions SQL intégrées dans PL/SQL
Ces instructions sont utilisables avec pratiquement la même syntaxe qu’en SQL.
● La partie interrogation : SELECT.
● La partie manipulation : INSERT, UPDATE, DELETE.
● La partie gestion des transactions : COMMIT, ROLLBACK, SAVEPOINT...
● Les fonctions TO_CHAR, TO_DATE, UPPER, SUBSTR, ROUND...
3. Instructions spécifiques au PL/SQL
Les caractéristiques procédurales de PL/SQL apportent les possibilités suivantes :
● la gestion des variables (déclaration, valorisation, utilisation),
● les structures de contrôle (séquence, test, boucles).
Des fonctionnalités supplémentaires sont disponibles :
● la gestion des curseurs (traitement du résultat d’une requête ligne par ligne),
● les traitements d’erreurs (déclaration, action à effectuer).
PL/SQL n’interprète pas une commande, mais un ensemble de commandes contenues dans un "bloc" PL/SQL. Ce bloc
est compilé et exécuté par le moteur PL/SQL du produit ou de la base.
Structure d’un bloc PL/SQL
Un bloc est composé de trois sections.
DECLARE
(déclaration des variables, des constantes, des exceptions
et des curseurs)
BEGIN
(instruction SQL, PL/SQL, structures de contrôle)
EXCEPTION
(traitement des erreurs)
END ;
Il est possible d’ajouter des commentaires à un bloc :
permet de mettre en commentaire ce qui suit sur la ligne.
/*... ... */
permet de mettre en commentaire plusieurs lignes.
Des étiquettes (label) permettent de marquer des parties de bloc, sous la forme <<nometiquette>>.
La section DECLARE qui permet de déclarer les variables qui vont être utilisées dans le bloc PL/SQL n’est nécessaire
que si le bloc a besoin de définir des variables. De même, la section EXCEPTION ne sera présente que dans les blocs
qui vont gérer les erreurs.
En PL/SQL, elles permettent de stocker des valeurs issues de la base ou de calculs, afin de pouvoir effectuer des tests,
des calculs ou des valorisations d’autres variables ou de données de la base.
Les variables sont caractérisées par :
● leur nom, composé de lettres, chiffres, $, _ ou # . Un maximum de 30 caractères est possible. Ce ne doit pas
être un nom réservé.
● leur type, qui détermine le format de stockage et d’utilisation de la variable.
Les variables doivent être obligatoirement déclarées avant leur utilisation.
Comme SQL, PL/SQL n’est pas sensible à la casse. Les noms des variables peuvent donc être saisis indifféremment en
minuscules ou en majuscules.
1. Variables locales
Déclaration
PL/SQL dispose de l’ensemble des types utilisables dans la définition des colonnes des tables dans le but de faciliter
les échanges de données entre les tables et les blocs de code. Cependant, les étendues des valeurs possibles pour
chacun de ces types peuvent être différentes de celles du SQL.
Il dispose également d’un certain nombre de types propres, principalement pour gérer les données numériques.
Enfin, PL/SQL permet de définir des types complexes basés soit sur des structures issues des tables, soit sur des
descriptions propres à l’utilisateur.
Syntaxe
nom-de-variable [CONSTANT]
type [[NOT NULL]:=expression] ;
CONSTANT
La valeur de la variable n’est pas modifiable dans le code de la section BEGIN.
NOT NULL
Empêche l’affectation d’une valeur NULL à la variable, expression doit être fournie.
expression
Valeur initiale affectée à la variable lors de l’exécution du bloc.
2. Types prédéfinis
a. Types caractères
CHAR[(n)]
Chaîne de caractères de longueur fixe avec n compris entre 1 et 32767. Si aucune taille maximale n’est précisée alors
la valeur utilisée par défaut est 1. Il faut également garder présent à l’esprit que la longueur maximale d’une colonne
de type CHAR est 2000, et il est donc impossible d’insérer une valeur de plus de 2000 caractères dans une telle
colonne.
VARCHAR2[(n)]
Chaîne de caractères de longueur variable avec n compris entre 1 et 32767 et représentant le nombre maximum
d’octets alloués à la variable. Il faut également considérer que la longueur maximale d’une colonne de type
VARCHAR2 est 4000 octets, et il est donc impossible d’insérer une valeur de plus de 4000 caractères dans une telle
colonne.
LONG
Chaîne de caractères de longueur variable comprenant au maximum 32760 octets.
RAW[(n)]
Chaîne de caractères ou données binaires de longueur variable avec n compris entre 1 et 32767. Le contenu d’une
variable de ce type n’est pas interprété par PL/SQL (pas de gestion des caractères nationaux).
LONG RAW
Identique au type LONG, mais PL/SQL n’en interprète pas le contenu.
En règle générale, un octet suffit à coder tous les caractères présents dans une langue. Mais certaines langues
comme le japonais, le chinois... possèdent trop de caractères pour pouvoir tous les coder sur un octet. Oracle offre
donc une solution pour coder ces caractères sur plusieurs octets. Le nombre d’octets dépend de la langue fixée au
moyen de NLS (National Language Support).
NCHAR[(n)]
NVARCHAR2[(n)]
Chaîne de caractères de longueur variable. N compris entre 1 et 32767.
Le nombre de caractères effectivement stockés dépend du nombre d’octets utilisés pour coder chaque caractère
dans le jeux de caractères choisi.
UROWID, ROWID
Permet de définir des variables dont la valeur représente l’adresse absolue de stockage d’une ligne d’une table sous
forme d’une chaîne de caractères.
Les valeurs de type ROWID sont composées de la façon suivante : OOOOOOFFFBBBBBBRRR et se décomposent en
quatre parties :
OOOOOO
Permet de connaître le numéro de l’objet qui possède cette ligne. En effet, il est nécessaire de connaître l’objet qui
possède la ligne d’information car, dans le cas de cluster, plusieurs objets peuvent partager le même segment.
FFF
Le numéro du fichier qui contient la ligne d’information. Le numéro de fichier est unique dans la base de données.
BBBBBB
Le numéro du bloc qui contient la ligne d’information. Le numéro du bloc est relatif au fichier et non pas au
tablespace.
RRR
Permet de connaître le numéro de la ligne dans le bloc.
Le type de données UROWID est utilisé par Oracle dans les tables qui n’ont pas de ROWID physique (par
exemple, les tables organisées en index).
b. Types numériques
NUMBER[(p,s)]
Nombres réels avec p chiffres significatifs stockés et un arrondi à droite de la marque décimale à s chiffres.
BINARY_INTEGER
Nombre entier compris entre 2 147 483 647 et +2 147 483 647.
PLS_INTEGER
Nombre entier compris entre 2 147 483 647 et +2 147 483 647.
Les variables de type PLS_INTEGER et BINARY_INTEGER nécessitent moins d’espace mémoire que celles de type
NUMBER. Les variables de type PLS_INTEGER et BINARY_INTEGER permettent des calculs plus rapides que celles de
type NUMBER.
c. Types pour les grands objets
Les variables déclarées avec les types suivants permettent de stocker des données non structurées (dont la
structure n’est pas gérée par PL/SQL) de grande taille.
BFILE
BLOB
32
Permet de stocker un objet binaire jusqu’à 2 1 blocs Oracle.
CLOB
32
Permet de stocker un ensemble de caractères, codés sur un octet, jusqu’à 2 1 blocs Oracle.
NCLOB
32
Permet de stocker un ensemble de caractères, codés sur un octet ou plusieurs octets, jusqu’à 2 1 blocs Oracle.
d. Autres types
BOOLEAN
Stocke des valeurs logiques TRUE, FALSE ou la valeur NULL.
DATE
Stocke une date dans un format de longueur fixe. La plage de date valide va du 1er janvier 4712 avant JC au 31
décembre 9999 après JC.
TIMESTAMP
Permet d’étendre le type DATE en conservant des fractions de secondes en plus des informations de type année,
mois, jour, heure, minute et seconde. Par défaut, la précision des fractions de secondes est exprimée sur 6 chiffres
mais elle peut s’étendre de 0 à 9 chiffres.
e. Soustypes
PL/SQL propose des soustypes synonymes des types donnés cidessus. Ces soustypes permettent d’assurer la
compatibilité avec les types standards ANSI/ISO et IBM.
Type ORACLE Soustypes
NUMBER DEC, DECIMAL, NUMERIC, DOUBLE PRECISION, FLOAT, REAL INTEGER, INT, SMALLINT
BINARY_INTEGER NATURAL, NATURALN, POSITIVE, POSITIVEN, SIGNTYPE
VARCHAR2 STRING, VARCHAR
CHAR CHARACTER
3. Types définis par l’utilisateur
PL/SQL autorise la définition de nouveaux types propres à une application. Ces types structurés permettent de définir
des variables qui regroupent sous un nom plusieurs valeurs de même type ou de type différent.
Pour chaque type de données il existe une plage des valeurs possibles et un ensemble d’opérations qui travaillent
avec ce type de données. Les soustypes permettent d’utiliser les mêmes opérations mais la plage des valeurs
possibles est réduite. On peut donc dire que les soustypes n’introduisent pas de nouveaux types de données mais ils
permettent au contraire de poser des contraintes sur des types de données existants.
Le but des soustypes est de simplifier l’écriture et la compréhension du programme en utilisant des noms de types de
données déjà connus par le programmeur ou utilisés dans l’entreprise. Par exemple, le type de données CHARACTER
est un soustype de CHAR pour que le langage PL/SQL respecte la norme ANSI.
Après la définition des soustypes dans la section DECLARE du bloc PL/SQL, il est possible d’y définir des variables de
Exemple
Définition et utilisation d’un soustype : déclaration du soustype datenaissance et utilisation dans un bloc PL/SQL.
4. Collections et enregistrements
Les collections et les enregistrements ont pour but de faciliter la programmation en PL/SQL. Ces types de données
n’existent qu’en PL/SQL et ne trouvent pas leur équivalent dans la base Oracle. Il n’est pas possible de stocker un
enregistrement directement dans la base mais par contre, il est tout à fait possible de stocker chaque élément qui
compose l’enregistrement dans la base.
a. Les collections
Une collection est un ensemble ordonné d’éléments de même type. Une collection peut être comparée aux tableaux
qu’il est possible de définir dans certains langages de programmation mais à cette différence que les collections ne
peuvent avoir qu’une seule dimension et que les éléments de la collection sont indexés par une valeur de type
numérique ou chaîne de caractères.
Parmi les collections il faut distinguer deux types différents : les tables (TABLE) qui sont de type index by table ou
nested table (qui étend les fonctionnalités offertes par les tables de type index) et les tableaux de type VARRAY.
Après la déclaration, les collections nested table et VARRAY doivent être initialisées. Pour cela, il existe une fonction
particulière, nommée constructeur, qui porte le même nom que la collection et qui accepte en paramètres les valeurs
que contient initialement la collection. Attention, ce constructeur n’est pas appelé implicitement par Oracle.
Les collections de type nested table et Index by table
Ces collections sont de taille dynamique et il n’existe pas forcément de valeurs pour toutes les positions.
Les collections
Comme le montre le schéma cidessus, les collections sont beaucoup plus souples que les tableaux, car il est
possible de supprimer des éléments particuliers de la collection.
Les collections de type nested table présentent la particularité que les données qu’elles contiennent peuvent être
stockées directement dans une colonne de table, d’où leur nom. De plus, les collections non initialisées sont NULL.
Les collections de type indexby table représentent quant à elle la méthode la plus rapide pour transférer des
données entre un bloc PL/SQL et la base de données.
Syntaxes
Déclaration d’une collection de type nested table.
Déclaration d’une collection de type indexby table
Exemple
Déclaration et utilisation de collections : dans l’exemple ciaprès, deux collections sont définies puis sont utilisées pour
valider leur définition (l’utilisation des collections sera détaillée ultérieurement dans ce chapitre).
Les collections de type VARRAY
Une collection de type VARRAY possède une dimension maximale qui doit être précisée lors de la déclaration de la
collection. Ces collections possèdent une longueur fixe et donc la suppression d’éléments ne permet pas de gagner
de la place en mémoire. Les éléments sont numérotés à partir de la valeur 1.
Syntaxe
nom_type
Représente le nom de la collection.
taille_maxi
Représente le nombre maximum d’éléments présents dans la collection.
type_element
Représente le type de données des éléments qui constituent la collection.
Exemple
Déclaration et utilisation de collections : dans l’exemple suivant, une collection nommée Calendrier est définie.
b. Les enregistrements
Un enregistrement est un ensemble de valeurs liées entre elles et regroupées sous un même nom. Chaque valeur
est stockée dans un champ. Par exemple, l’enregistrement qui permet de manipuler un client sera composé des
champs numéro, nom, adresse... Les enregistrements représentent donc un moyen simple de manipuler les
informations qui sont liées entre elles.
Pour pouvoir créer un enregistrement, il est nécessaire au préalable, de définir le type d’enregistrement dans la
section DECLARE du bloc PL/SQL.
Record
Un RECORD est un regroupement d’éléments de types différents logiquement liés entre eux et désignés par un nom
unique.
Syntaxe
type_champs correspond à un type PL/SQL défini plus haut.
Les champs d’une variable de type RECORD peuvent être référencés à l’aide de l’opérateur "." :
Nom_variable.nom_champs
Exemple
Définition d’un RECORD client reprenant les informations relatives à un client :
SQL> declare
2 type T_CLIREC is record (
3 NOCLI number(4),
4 NOM char(20),
5 ADR char(20),
6 CODPOST number(5));
7 UNCLIENT T_CLIREC ;
8 begin
9 -- Instructions
10 UNCLIENT.NOCLI := 1024;
11 -- Instructions
12 end;
13 /
SQL>
Comme pour la déclaration des variables, il est possible d’initialiser les champs lors de leur déclaration et de
les rendre obligatoires ou non.
5. Types dérivés
%TYPE
L’attribut %TYPE permet de référencer soit une colonne d’une table, soit une variable précédemment définie.
Syntaxe
nom-de-variable nomdetable.nomdecolonne%TYPE;
ou
nom-de-variable2 nomdevariable1%TYPE;
Exemple
%ROWTYPE
On peut référencer des structures entières de table ou de curseur afin de créer des variables qui seront composées
de la même structure.
Syntaxe
Exemple
6. Variables définies dans un environnement extérieur à PL/SQL
Ces variables sont déclarées en dehors du bloc et utilisables dans le bloc.
Ce sont des champs d’écran créés dans Oracle*Forms, ou des variables définies en langage hôte par les
précompilateurs ou par SQL*Plus (ces variables sont toujours préfixées de ":" dans un bloc PL/SQL).
Exemple
Utilisation d’une variable de lien SQL*Plus (x) :
Les variables sont utilisées soit pour leur affecter une valeur, soit en tant qu’expression dans les tests ou les
modifications de données.
a. Affectation de valeur
Plusieurs possibilités de valorisation de variables sont possibles.
:=
L’affectation directe de valeur.
Syntaxe
nom-de-variable := expression ;
L’expression peut être soit une constante, soit une variable, soit un calcul portant sur des constantes et des
variables.
Les opérateurs de calcul sont les suivants :
opérateurs arithmétiques + ; ; * ; / ; **(exponentiation)
opérateur de concaténation ||
On peut utiliser les parenthèses pour grouper les calculs.
L’écriture des constantes suit les mêmes règles qu’en SQL.
Exemple
Valorisation de variables (dans la section BEGIN) :
x := 0 ;
Vnom := ’Monsieur’|| Vnom ;
y := (x + 5) * y ;
INTO
La clause INTO des instructions SELECT et FETCH du PL/SQL permet la valorisation des variables à partir d’une ligne
issue d’une requête (et une seule).
Syntaxe
Exemple
Valorisation de variables à partir de tables de la base :
DECLARE
Vref CHAR(10) ;
Vprix ARTICLES.PRIXHT%TYPE ;
Cli CLIENTS%ROWTYPE ;
BEGIN
select REFART, PRIXHT into Vref, Vprix from Articles
where DESIGNATION = ’Cadeau’ ;
select * into Cli from CLIENTS where NOCLI = 10 ;
b. Utilisation
Les valeurs stockées dans les variables peuvent être utilisées en tant qu’expression dans les commandes SQL ou
PL/SQL.
Exemple
Modification de la table CLIENTS à partir des valeurs de variables :
BEGIN
Vnom := ’Dupont’ ;
UPDATE CLIENTS SET NOM = Vnom where NOCLI = Vnocli ;
Vnocli := Vnocli + 1 ;
INSERT INTO CLIENTS (NOCLI, NOM) VALUES (Vnocli, Vnom) ;
COMMIT ;
END ;
c. Visibilité
Une variable est visible dans le bloc où elle a été déclarée, et dans les blocs imbriqués si elle n’a pas été redéfinie.
Exemple
Test de la visibilité des variables dans des blocs PL/SQL imbriqués :
8. Variables structurées et instruction du DML
Il est possible d’utiliser une variable de type structuré dans une opération INSERT pour ajouter des données dans une
table de la base depuis un bloc PL/SQL.
Exemple
L’exemple cidessous montre la mise en place de cette possibilité depuis le bloc PL/SQL. La variable structurée vcli est
composée de champs. Chacun de ces champs est destiné à recevoir une valeur d’une colonne de la table CLIENTS. Les
différents champs sont renseignés puis cette variable est utilisée directement dans la commande INSERT.
declare
vcli clients%rowtype;
begin
-- renseigner les différents champs de la variable structurée
vcli.nocli :=100;
vcli.nomcli :=’MOORE’;
vcli.adrcli :=’13 rue de la croissance’;
vcli.code_postal:=’69004’;
vcli.ville:=’LYON’;
Le travail avec les variables structurées est également possible pour les opérations de mise à jour avec les
instructions UPDATE. Pour cela, la variable structurée doit contenir un champ pour chaque colonne de la table et c’est
donc la totalité de la ligne qui est mise à jour d’un coup. La commande UPDATE utilise alors l’instruction SET ROW=
variable composée.
Exemple
Il est parfois nécessaire d’aller lire les données nouvellement insérées, supprimées ou mises à jour. L’opération
habituelle consiste à utiliser un ordre SELECT pour connaître la valeur des colonnes après mise à jour. Il est possible
de demander aux instructions INSERT, UPDATE ou DELETE de retourner la valeur des colonnes nouvellement mises à
jour par l’intermédiaire de la clause RETURNING. Bien sûr, il est possible d’utiliser cette clause uniquement si la
commande SQL DML a porté sur exactement une ligne de données.
Exemple
L’exemple suivant permet de connaître la valeur du prix d’un article après son augmentation de 10%.
declare
type rec_art_info is record(
refart char(4),
prix number(8,2)
);
art_info rec_art_info;
begin
update articles set prix=prix*1.1
where refart=’AB01’
returning refart, prix into art_info;
-- art_info contient les valeurs après mise à jour
end;
/
Les trois structures de contrôles sont :
● la séquence : exécution d’instructions les unes après les autres.
● l’alternative : exécution d’instructions en fonction d’une condition.
● la répétitive : exécution d’instructions plusieurs fois en fonction d’une condition.
1. Traitements conditionnels
If
Il permet l’exécution d’instructions en fonction du résultat d’une condition.
Syntaxe
Les opérateurs utilisés dans les conditions sont les mêmes que dans SQL :
=; <, >, !, >=, <=, IS NULL, IS NOT NULL, BETWEEN, LIKE, AND, OR, etc.
Exemple
Si le client 10 est en cours de traitement, on le met à jour sinon on annule la transaction :
if Vnocli = 10 THEN
UPDATE CLIENTS SET NOM = ’Dupont’ where NOCLI = Vnocli ;
COMMIT ;
else
ROLLBACK ;
end if ;
CASE
L’instruction CASE permet une exécution conditionnelle comme l’instruction IF. Cependant, cette instruction CASE est
particulièrement bien adaptée aux conditions comportant de nombreux choix différents. Elle permet une présentation
plus lisible du code, donc moins de risque d’erreur. De plus, l’utilisation du CASE est susceptible d’améliorer les
performances au cours de l’exécution.
Syntaxe
[<<étiquette>>]
CASE element_de_selection
WHEN valeur1 THEN instructions1;
WHEN valeur2 THEN instructions2;
...
[ELSE instructions;]
END CASE [étiquette];
[<<étiquette>>]
CASE
WHEN condition1 THEN instructions1;
WHEN condition2 THEN instructions2;
...
[ELSE instructions;]
END CASE [étiquette];
La condition ELSE est optionnelle et elle n’est exécutée que si aucune des conditions WHEN précédentes n’est
exécutée. En l’absence de définition de la condition ELSE, PL/SQL ajoute implicitement la condition ELSE
suivante : ELSE RAISE CASE_NOT_FOUND (ce qui génère une exception).
L’instruction CASE peut se présenter sous deux formes : dans un premier cas, soit la valeur à tester suit
immédiatement le CASE et c’est alors un test d’égalité qui est fait avec chaque valeur suivant les instructions WHEN
pour déterminer s’il faut ou non exécuter les instructions PL/SQL associées. Dans sa deuxième forme, chaque
instruction WHEN est suivie d’une condition, et c’est l’évaluation de cette condition à vraie qui permet d’exécuter les
instructions associées PL/SQL.
Dans tous les cas, les instructions WHEN sont évaluées de façon séquentielle et seule la première évaluée à vraie est
exécutée.
Exemples
L’exemple suivant permet de comparer la valeur contenue dans la variable département avec chacune des valeurs qui suit le
WHEN.
declare
departement number:=44;
libelle varchar2(40);
begin
case departement
when 44 then libelle:=’Loire Atlantique’;
when 49 then libelle:=’Maine et Loire’;
when 53 then libelle:=’Mayenne’;
Dans l’exemple cidessous la condition de chaque instruction WHEN est évaluée pour savoir s’il est nécessaire d’exécuter ou
non les instructions placées dernière le mot clé THEN.
declare
departement number:=44;
region varchar2(40);
begin
case
when departement in (18,28,36,37,41,45)
then region:=’Centre’;
when departement in (75,77,78,91,92,93,94,95)
then region:=’Ile de France’;
when departement in (44,49,53,72,85)
then region:=’Pays de la loire’;
end case;
end;
/
Ce dernier exemple permet de mettre en évidence la possibilité d’imbriquer les instructions CASE les unes dans les autres.
Avec ce type d’imbrication, il faut prendre en compte les problèmes de clarté du code.
set serveroutput on
declare
departement number:=44;
region varchar2(80);
libelle varchar2(80);
begin
case
when departement in (18,28,36,37,41,45) then
region:=’Centre’;
when departement in (75,77,78,91,92,93,94,95) then
region:=’Ile de France’;
when departement in (44,49,53,72,85) then
region:=’Pays de la loire’;
case departement
when 44 then libelle:=’Loire Atlantique’;
when 49 then libelle:=’Maine et Loire’;
when 53 then libelle:=’Mayenne’;
when 72 then libelle:=’Sarthe’;
when 85 then libelle:=’Vendée’;
else libelle:=’Hors Region’;
end case;
end case;
dbms_output.put_line(’region:’||region);
end;
/
2. Traitements répétitifs
Ce sont des ensembles d’instructions écrites une seule fois et exécutées à plusieurs reprises.
LOOP
PL/SQL permet d’effectuer des traitements répétitifs grâce à la clause LOOP.
Utilisé seul, LOOP initialise des boucles sans fin et systématiques.
Syntaxe
[<<LABEL>>]
LOOP
instructions;
Sortie de la boucle par la commande :
où LABEL est le nom de la boucle et condition la condition qui doit être vraie pour la sortie.
Exemple
Insertion de 10 lignes dans CLIENTS :
x := 0 ;
<<INCREMENTATION>>
LOOP
x := x + 1 ;
exit INCREMENTATION when x > 10 ;
insert into CLIENTS (NOCLI) VALUES (x) ;
END LOOP INCREMENTATION ;
COMMIT ;
L’instruction CONTINUE permet d’interrompre l’itération en cours et de passer immédiatement à la suivante ; cette
instruction est apparue en version 11.
La syntaxe est semblable à celle de l’instruction EXIT :
où LABEL est le nom de la boucle et condition la condition qui doit être vraie pour que l’exécution passe à l’itération
suivante.
Exemple :
Insérer uniquement des clients avec des numéros impairs.
x := 0;
<<INCREMENTATION>>
LOOP
x := x + 1;
exit INCREMENTATION when x > 10 ;
continue INCREMENTATION when mod(x,2) = 0 ;
insert into CLIENTS (NOCLI) VALUES (x) ;
END LOOP INCREMENTATION ;
COMMIT;
FOR
La boucle FOR permet d’exécuter les instructions de la boucle en faisant varier un indice.
Les instructions sont exécutées autant de fois que l’indice change de valeur.
L’indice peut être utilisé dans les instructions comme une variable (en lecture).
Syntaxe
[<<LABEL>>]
FOR indice IN [REVERSE] exp1..exp2 LOOP
instructions;
....
END LOOP [LABEL];
L’indice est déclaré implicitement.
exp1, exp2 sont des constantes, expressions ou variables.
Sans l’option REVERSE, indice varie de exp1 à exp2 avec un incrément de 1.
Avec l’option REVERSE, indice varie de exp2 à exp1 avec un incrément de 1.
Exemple
Création de 10 clients avec numéros successifs :
WHILE
L’entrée dans la boucle se fait si la condition est vraie.
Les instructions sont ensuite exécutées tant que cette condition reste vraie.
Syntaxe
[<<LABEL>>]
WHILE condition LOOP
instructions;
......
END LOOP [LABEL];
La condition est une combinaison d’expressions au moyen d’opérateurs :
<, >, =, !=, AND, OR, LIKE,..
Exemple
Création de 11 clients consécutifs :
x := 200 ;
while x <= 210 LOOP
insert into CLIENTS (NOCLI) values (x) ;
x := x + 1 ;
end loop ;
COMMIT ;
1. Définition
Le curseur est une zone de mémoire de taille fixe, utilisé par le moteur de la base Oracle pour analyser et interpréter
tout ordre SQL.
Les statuts d’exécution de l’ordre se trouvent dans le curseur.
Il existe deux types de curseurs :
Le curseur implicite
Curseur SQL généré et géré par ORACLE pour chaque ordre SQL.
Le curseur explicite
Curseur SQL généré et géré par l’utilisateur pour traiter un ordre SELECT qui ramène plusieurs lignes.
2. Étape d’utilisation d’un curseur explicite
a. Déclaration
Tout curseur explicite utilisé dans un bloc PL/SQL doit être déclaré dans la section DECLARE du bloc en donnant :
● son nom,
● l’ordre SELECT associé.
Syntaxe
b. Ouverture
Après avoir déclaré le curseur, on "ouvre" celuici pour faire exécuter l’ordre SELECT.
L’ouverture déclenche :
● l’allocation mémoire du curseur,
● l’analyse syntaxique et sémantique de l’ordre SELECT,
● le positionnement de verrous éventuels (si SELECT ... FOR UPDATE).
L’ouverture du curseur se fait dans la section BEGIN du bloc.
Syntaxe
OPEN nom_curseur;
c. Traitement des lignes
Après l’exécution du SELECT, les lignes ramenées sont traitées une par une, la valeur de chaque colonne du SELECT
doit être stockée dans une variable réceptrice.
Syntaxe
d. Fermeture
Après le traitement des lignes pour libérer la place mémoire, on ferme le curseur.
Syntaxe
CLOSE nom_curseur;
e. Curseur for
Dans la mesure où l’utilisation principale d’un curseur est le parcours d’un ensemble de lignes ramenées par
l’exécution du SELECT associé, il peut être intéressant d’utiliser une syntaxe plus simple pour l’ouverture du curseur
et le parcours de la boucle.
Oracle propose une variante de la boucle FOR qui déclare implicitement la variable de parcours, ouvre le curseur,
réalise les FETCH successifs et ferme le curseur.
Syntaxe
Exemple
Définition et parcours d’un CURSOR sur la table CLIENTS. Affichage du dernier client lu dans la table.
SQL> declare
2 cursor c_cli is select NOCLI, NOMCLI from CLIENTS;
3 begin
4 for V_CLI in C_CLI LOOP
5 :NO_CLIENT := V_CLI.NOCLI;
6 :NOM_CLIENT := V_CLI.NOMCLI;
7 end loop ;
8 end;
9 /
NO_CLIENT
---------
152
NOM_CLIENT
------------
LAROCHE
SQL>
Il est également possible de ne pas déclarer le curseur dans la section DECLARE mais de spécifier celuici directement dans
l’instruction FOR.
SQL> begin
2 for V_CLI in (select NOCLI, NOMCLI from CLIENTS) LOOP
NOM_CLIENT
---------------------
LAROCHE
SQL>
3. Les attributs d’un curseur
Les attributs d’un curseur (implicite ou explicite) sont des indicateurs sur l’état d’un curseur.
%FOUND
C’est un attribut de type booléen.
Nom de l’attribut pour un curseur implicite : SQL%FOUND
Il est à TRUE (vrai) si :
● la dernière instruction INSERT, UPDATE ou DELETE a traité au moins une ligne,
● ou si le dernier SELECT ... INTO a ramené une et une seule ligne.
Nom de l’attribut pour un curseur explicite : nom_curseur%FOUND
Il est à TRUE si le dernier FETCH a ramené une ligne.
%NOTFOUND
C’est un attribut de type booléen.
Nom de l’attribut pour un curseur implicite : SQL%NOTFOUND
Il est à TRUE ( vrai ) si :
● la dernière instruction INSERT, UPDATE, ou DELETE n’a traité aucune ligne,
● ou si le dernier SELECT ... INTO n’a pas ramené de ligne (dans ce cas une exception est d’abord générée, cf.
Gestion des erreurs dans ce chapitre).
Nom de l’attribut pour un curseur explicite : nom_curseur%NOTFOUND
Il est à TRUE si le dernier FETCH n’a pas ramené de ligne.
%ISOPEN
C’est un attribut de type booléen.
Nom de l’attribut pour un curseur implicite : SQL%ISOPEN
Toujours à FALSE car ORACLE referme les curseurs après utilisation.
Nom de l’attribut pour un curseur explicite : nom_curseur%ISOPEN
Il est à TRUE si le curseur est ouvert.
Nom de l’attribut pour un curseur implicite : SQL%ROWCOUNT
Il contient le nombre de lignes traitées par le dernier INSERT, UPDATE ou DELETE.
Il est à 0 si le dernier SELECT...INTO n’a ramené aucune ligne, à 1 si le dernier SELECT... INTO a ramené exactement 1
ligne, ou à 2 si SELECT...INTO a ramené plus d’une ligne (mais une exception est d’abord générée si le nombre de
ligne retournée est différent de 1, cf. Gestion des erreurs dans ce chapitre).
Nom de l’attribut pour un curseur explicite : nom_curseur%ROWCOUNT
Indique le numéro de la ligne ramenée par le dernier FETCH.
Bien entendu, tous les attributs ne sont pas testables n’importe comment. Le tableau cidessous indique la valeur à
laquelle on peut s’attendre lorsque l’on teste l’un de ces attributs.
4. ROWNUM
La variable ROWNUM retourne un numéro indiquant l’ordre dans lequel la ligne a été sélectionnée depuis une table. La
première ligne sélectionnée porte le numéro 1, la deuxième le numéro 2... Si la commande SELECT, d’extraction des
lignes, contient une clause ORDER BY, alors ROWNUM contient le numéro de la ligne avant le tri des données.
Exemple
Utilisation de ROWNUM : dans l’exemple suivant, la variable ROWNUM est utilisée pour extraire les trois premiers clients.
La clause CURRENT OF permet d’accéder directement en modification ou en suppression à la ligne que vient de
ramener l’ordre FETCH.
Il faut au préalable réserver les lignes lors de la déclaration du curseur par un verrou d’intention (... FOR UPDATE OF
nom_col...).
Cette fonctionnalité est très importante car la clause FOR UPDATE permet de poser un verrou d’intention, c’estàdire
que les données ne peuvent pas être modifiées, par un autre utilisateur, entre le moment où les données sont lues et
le moment où les données sont modifiées. Sans ce verrou d’intention, des modifications peuvent avoir lieu entre la
lecture et la mise à jour, ce qui peut avoir des conséquences non négligeables.
De plus, la clause CURRENT OF permet de ne pas manipuler la clé primaire.
Exemple
Utilisation d’un curseur pour la mise à jour de chaque ligne traitée :
Declare
CURSOR C1 is
Select REFART, PRIXHT from ARTICLES
FOR UPDATE OF PRIXHT ;
ART C1%ROWTYPE ;
BEGIN
Open C1 ;
fetch C1 into ART ;
while C1%FOUND loop
update ARTICLES set PRIXHT = ART.PRIXHT * 2
where current of C1 ;
fetch C1 into ART ;
end loop ;
commit ;
close C1 ;
END ;
6. Passage de paramètres
Il est possible de définir les curseurs avec des paramètres afin de rendre leur utilisation la plus souple possible. Le
passage de paramètres s’effectue à l’ouverture du curseur par la commande OPEN.
Syntaxe
Déclaration du curseur avec paramètres :
Ouverture du curseur paramétré et passage de la valeur des paramètres :
Exemple
Utilisation d’un curseur paramétré : dans l’exemple suivant, le curseur accepte en paramètre le numéro du client et permet
de connaître les numéros des commandes passées par ce client.
Le langage PL/SQL fournit un mécanisme d’interception des erreurs afin de donner une réponse logicielle à tout type
d’erreur. Bien sûr, toutes les erreurs ne pourront être traitées mais il est possible de prévoir une sortie propre du
programme quoi qu’il arrive.
Le traitement des erreurs a lieu dans la partie EXCEPTION du bloc PL/SQL. Cette partie est optionnelle et ne doit être
définie que si le bloc intercepte des erreurs.
Structure d’un bloc PL/SQL :
La section EXCEPTION permet d’affecter un traitement approprié aux erreurs survenues lors de l’exécution du bloc
PL/SQL.
On distingue deux types d’erreurs :
● les erreurs internes Oracle,
● les anomalies dues au programme.
Après l’exécution du code correspondant au traitement de l’exception, le bloc en cours d’exécution est terminé, et
l’instruction suivante à être exécutée est celle qui suit l’appel à ce bloc PL/SQL dans le bloc maître.
Les avantages de ce mode de gestion des erreurs sont nombreux. Le plus important est représenté par le fait que pour
gérer un type d’erreur, le code ne doit être écrit qu’une seule fois. Dans les langages de programmation qui ne
possèdent pas ce mécanisme d’interception des erreurs, l’appel à la fonction traitant l’erreur doit être précisé à chaque
fois que l’erreur peut se produire.
Schéma résumant le principal avantage d’un mécanisme d’interception des erreurs :
Règles à respecter
● Définir et donner un nom à chaque erreur (différent pour les erreurs utilisateur et les erreurs Oracle).
● Associer une entrée dans la section EXCEPTION pour chaque nom d’erreur défini dans la partie DECLARE.
● Définir le traitement à effectuer dans la partie EXCEPTION.
La levée des exceptions ne permet pas de continuer normalement le traitement des opérations.
Toutefois, en s’appuyant sur la définition de sousblocs au sein desquels les exceptions sont gérées, il est possible
d’exécuter une suite d’instructions même si une exception est levée au cours de l’exécution d’un sousbloc.
1. Erreurs prédéfinies
Toutes les erreurs Oracle possèdent un numéro d’identification unique. Mais elles ne peuvent être interceptées dans
un bloc PL/SQL que si un nom est associé au numéro de l’erreur Oracle. Dans le langage PL/SQL, les erreurs Oracle les
plus courantes sont associées à un nom afin de faciliter leur interception dans les blocs PL/SQL.
La liste de ces exceptions prédéfinies est donnée cidessous. Pour traiter les autres erreurs Oracle, il est toujours
possible d’utiliser le mot clé OTHERS et de connaître l’exception à l’origine de ce traitement en faisant appel aux
fonctions SQLCODE et SQLERRM.
Les exceptions prédéfinies appartiennent au package STANDARD, aussi ces exceptions sont utilisables telles quelles
dans les programmes PL/SQL
Les exceptions sont traitées dans la partie EXCEPTION du bloc PL/SQL. À l’intérieur de cette partie, les clauses WHEN
permettent de connaître le code à exécuter en réponse à une exception levée.
Exemple
Gestion de l’exception Oracle prédéfinie TOO_MANY_ROWS : dans l’exemple ciaprès, la partie exception du bloc PL/SQL
permet de traiter les exceptions qui correspondent à une tentative de stocker un ensemble de valeurs dans une seule
variable (TOO_MANY_ROWS).
2. Anomalies programme utilisateur
Si le programmeur pense qu’une anomalie peut se produire pendant le traitement (erreur logique ou erreur de
données), il peut le prévoir comme une exception qui permettra un traitement supplémentaire si elle se produit.
Les exceptions peuvent être définies uniquement dans la section DECLARE du bloc PL/SQL. Une exception est définie
en précisant son nom, suivi du mot clé EXCEPTION.
DECLARE
Depassement EXCEPTION
...
Dans l’exemple cidessus l’exception Depassement est définie.
La déclaration des exceptions est similaire à celle des variables.
Syntaxe
DECLARE
...
nom_erreur EXCEPTION;
...
BEGIN
...
IF(anomalie)
THEN RAISE nom_erreur;
...
EXCEPTION
WHEN nom_erreur THEN
(traitement);
END;
=> Sortie du bloc après exécution du traitement.
Exemple
Par rapport à l’exemple précédent (curseurs), on prévoit d’arrêter et d’annuler les modifications si un prix dépasse le plafond
fixé.
DECLARE
CURSOR C1 ...
ART ...
Depassement EXCEPTION ;
NVPRIX NUMBER ;
BEGIN
....
while C1%FOUND LOOP
NVPRIX := ART.PRIXHT *2 ;
if NVPRIX > 10000 then raise depassement ;
update ARTICLES set PRIXHT = NVPRIX ...
fetch ...
end loop ;
...
EXCEPTION
When depassement then
rollback ;
END ;
Le mot clé RAISE permet bien sûr de lever des erreurs utilisateurs dans la partie traitement du bloc, mais il est
également possible de l’utiliser pour propager des exceptions dans le bloc appelant après traitement partiel ou
complet d’une exception.
En effet, une exception se propage de bloc en bloc, jusqu’à trouver un traitement qui lui est approprié dans la section
exception. Après traitement de l’exception, le bloc courant est quitté pour revenir au bloc de niveau supérieur sans
erreur. Il peut parfois être nécessaire de faire remonter une exception après le traitement d’exception. Pour cela, on
utilise le mot clé RAISE suivi du nom de l’exception à propager au bloc de niveau supérieur.
Exemple
Utilisation de l’instruction RAISE pour propager une erreur : dans l’exemple suivant, le bloc PL/SQL et son sousbloc essaient
de supprimer une commande.
3. Erreurs Oracle
Pour capturer une erreur Oracle non prédéfinie il est nécessaire, soit de travailler avec la clause WHEN OTHERS du bloc
de traitement des exceptions, soit d’associer un nom au numéro de l’erreur Oracle que l’on souhaite capturer. Cette
association, nom d’exception et numéro d’erreur Oracle, est possible grâce à la directive de compilation PRAGMA
EXCEPTION_INIT.
Le nom associé à l’erreur Oracle doit être défini au préalable comme étant un nom d’exception.
Syntaxe
Exemple
Interception d’une erreur Oracle non prédéfinie : dans l’exemple ciaprès, le bloc PL/SQL traite l’erreur qui correspond à un
verrou mortel. Un verrou mortel survient lorsque les verrous posés sur les différentes lignes modifiées par les utilisateurs
bloquent tous les utilisateurs. Les verrous mortels sont détectés automatiquement par Oracle qui décide alors de libérer une
transaction pour l’autoriser à saisir l’ordre ROLLBACK afin de libérer les ressources et les utilisateurs.
Le traitement de cette exception sera donc simplement l’ordre ROLLBACK.
PL/SQL déclare des exceptions prédéfinies dans le package standard. Il ne faut surtout pas redéfinir ces
exceptions, car la définition locale de l’exception masque la déclaration globale. Par exemple, si l’on définit une
exception invalid_number associée à un code d’erreur Oracle, pour traiter l’exception prédéfinie qui porte ce nom, il
faudra préfixer le nom de l’exception par le nom de package, soit standard.invalid_number.
Toutes les erreurs dues au SQL ou au PL/SQL ont un code. Il est possible d’associer ce code à un nom d’exception afin
de prendre en compte le traitement de l’erreur au niveau du bloc.
Syntaxe
DECLARE
...
nom_erreur EXCEPTION;
PRAGMA EXCEPTION_INIT(nom_erreur, code_erreur);
...
BEGIN
...
=>Dès qu’une erreur Oracle est rencontrée, passage
automatique à la section EXCEPTION pour réaliser le trai-
tement approprié à l’erreur
...
EXCEPTION
WHEN nom_erreur THEN
(traitement);
[WHEN OTHERS THEN (traitement);]
END;
=> Sortie du bloc après exécution du traitement
Exemple
L’erreur 1401 signifie une valeur trop grande pour une colonne. Si elle se produit on veut tout arrêter proprement :
Declare
...
Trop_grand EXCEPTION ;
PRAGMA EXCEPTION_INIT (Trop_Grand, -1401) ;
Begin
...
...
Exception
When Trop_grand then rollback ;
end ;
4. Portée des exceptions
La visibilité des exceptions est similaire à celle des variables. En effet, une exception est visible dans le bloc où elle est
définie et dans tous les sousblocs de ce bloc. Toutefois, il est possible de masquer cette exception dans les sous
blocs en redéfinissant une exception qui porte le même nom.
Le sousbloc ne peut pas lever l’exception définie dans le bloc de niveau supérieur car elle est masquée par la
définition locale. Si le bloc de niveau supérieur porte une étiquette, il est possible de lever l’exception définie au niveau
supérieur en utilisant la syntaxe suivante : nom_du_bloc.nom_exception
Dans l’exemple ciavant les deux exceptions depassement sont totalement différentes et il n’existe aucun lien
entre elles.
5. Utilisation de raise_application_error
Le package DBMS_STANDARD, qui est installé avec Oracle, fournit un ensemble de fonctions et de procédures qui
facilitent le développement sous Oracle. Par exemple, la procédure raise_application_error permet de définir des
erreurs utilisateur depuis des sousprogrammes.
Syntaxe
numero_erreur
représente le numéro de l’erreur utilisateur. Ce numéro doit être compris entre 20000 et 20999.
message
chaîne de caractères d’une longueur maximale de 2048 octets qui contient le message associé à l’erreur.
Le troisième paramètre, qui est optionnel, permet de savoir si l’erreur doit être placée sur la pile des erreurs (TRUE) ou
bien si l’erreur doit remplacer toutes les autres erreurs. C’est cette dernière solution qui est adoptée par défaut.
Lorsque le bloc PL/SQL appelle la procédure raise_application_error, le déroulement de ce bloc est interrompu et
l’erreur est remontée au bloc appelant. Ce dernier doit traiter l’exception comme une erreur Oracle.
Exemples
Utilisation de raise_application_error : dans l’exemple suivant une erreur est levée si le client habite Nantes.
Bloc de suppression d’un client : dans ce second exemple, on utilise le principe de gestion des exceptions pour supprimer un
client.
Ce programme est exécuté via SQL*Plus.
1. Énoncé du traitement
On veut pouvoir mettre à jour la quantité en stock de la table ARTICLES (REFART, DESIGNATION, PRIXHT, QTESTK) à
partir des commandes en cours (ETATCDE = ’EC’) stockées dans les tables COMMANDES (NOCDE, NOCLI, DATCDE,
ETATCDE) et LIGNESCDE (NOCDE, NOLIG, REFART, QTECDE).
Le traitement doit mettre à jour la colonne QTESTK de ARTICLES en otant les QTECDE de LIGNESCDE pour l’article. Il
doit également y avoir mise à jour de ETATCDE à ’LI’ si toutes les quantités peuvent être livrées pour la commande
(QTESTK > 0 après décrémentation).
Dans le cas où la quantité en stock de l’article devient négative, les mises à jour pour cette commande sont annulées.
Une table témoin est mise à jour pour chaque article à problème (non livrable) et pour chaque commande livrée
entièrement.
2. Exemple
Script majliv.sql.
END;
/
rem Consultation de la table témoin
select * from temoin;
drop table temoin;
3. Exécution par SQL*Plus
9 ligne(s) sélectionnée(s).
SQL> @majliv
SQL> select * from temoin;
NOCDE TEXTE
---------- ----------------------------------------------------
1210 Problème sur article(s):AB10CD50
1230 Problème sur article(s):AB10
1250 Commande livrée
1301 Commande livrée
Table supprimée.
9 ligne(s) sélectionnée(s).
Exécution avant ou après vérification des contraintes d’intégrité pour chaque ligne ou chaque ordre.
Dans les triggers BEFORE et FOR EACH ROW, il est possible de modifier les données qui vont être insérées dans la table
pour qu’elles respectent les contraintes d’intégrité. Il est également possible de faire des requêtes de type SELECT sur
la table sur laquelle porte l’ordre DML uniquement dans le cadre d’un trigger BEFORE INSERT. Toutes ces opérations
sont impossibles dans les triggers AFTER car après vérification des contraintes d’intégrité, il n’est pas possible de
modifier les données et comme la modification (ou ajout, ou suppression) de la ligne n’est pas terminée, il n’est pas
possible d’effectuer des SELECT sur la table.
Il est également possible de poser des triggers sur les vues (VIEW) afin d’intercepter les ordres DML que l’on peut y
exécuter. Ces triggers permettent de maîtriser toutes les opérations qui sont effectuées sur les vues et pour l’utilisateur
final, la vue est en tout point similaire à une table puisqu’il peut y faire les opérations INSERT, UPDATE et DELETE. Ces
triggers sont de type INSTEAD OF, c’estàdire que leur exécution va remplacer celle de la commande DML à laquelle ils
sont associés. Ce type de trigger n’est définissable que sur les vues, et seul ce type de trigger peut être mis en place
sur les vues.
Principe de fonctionnement des triggers instead of
Syntaxe
Remplace la description du TRIGGER s’il existe déjà.
BEFORE
Le bloc PL/SQL est exécuté AVANT la vérification des contraintes de tables et la mise à jour des données dans la table.
AFTER
Le bloc PL/SQL est exécuté APRES la mise à jour des données dans la table.
INSTEAD OF
Le bloc PL/SQL qui suit remplace le traitement standard associé à l’instruction qui a déclenché le TRIGGER (pour une vue
uniquement).
Instruction associée au déclenchement du TRIGGER. Plusieurs instructions peuvent déclencher le même TRIGGER. Elles
sont combinées par l’opérateur OR.
Le TRIGGER s’exécute pour chaque ligne traitée par l’instruction associée.
FOLLOWS nom_autre_trigger[,...]
Oracle permet de définir plusieurs triggers pour la même table et le même événement. Dans ce cas, l’ordre relatif de
déclenchement de ces triggers est indéterminé. Si l’ordre de déclenchement de ces triggers est important pour votre
application, vous pouvez utiliser la clause FOLLOWS apparue en version 11. Cette clause permet d’indiquer que le
trigger doit être déclenché après les triggers mentionnés.
ENABLE/DISABLE
Cette clause permet d’indiquer si le trigger est actif ou non dès sa création ; par défaut, un trigger nouvellement créé
est actif. Créer un trigger désactivé permet de vérifier qu’il se compile correctement avant de le mettre réellement en
service. Un trigger créé désactivé peut ensuite être activé par un ordre ALTER TRIGGER … ENABLE.
WHEN (condition)
La condition donnée doit être vérifiée pour que le code s’exécute.
Les données de la table à laquelle est associé le TRIGGER sont inacessibles depuis les instructions du bloc. Seule la
ligne en cours de modification est accessible à l’aide de deux variables RECORD, OLD et NEW, qui reprennent la
structure de la TABLE ou de la VIEW associée. Ces variables peuvent être utilisées dans la clause WHEN du TRIGGER ou
dans le bloc d’instructions. Dans ce dernier cas, elles sont référencées comme des variables hôtes avec le préfixe
":" (:OLD.nom_champs, :NEW.nom_champs).
Le terme OLD permet de connaître la ligne en cours de suppression dans un trigger DELETE ou la ligne avant
modification dans un trigger UPDATE. Le terme NEW permet de connaître la nouvelle ligne insérée dans un trigger
INSERT ou la ligne après modification dans un trigger UPDATE.
Les termes OLD et NEW sont fixés par défaut et il est possible d’utiliser d’autres termes en précisant la clause
REFERENCING OLD AS nouveau_nom NEW AS nouveau_nom. Cette clause prend place juste avant la clause FOR EACH ROW
(si elle existe) dans la définition du trigger.
Exemple
Exécution d’un bloc PL/SQL avant une suppression dans la table CLIENTS du user FLORIAN :
Exécution d’un bloc PL/SQL après mise à jour de chaque ligne de la table ARTICLES si l’ancien prix est supérieur au nouveau :
Pour chaque commande on souhaite connaître le nom de l’utilisateur Oracle qui a réalisé la saisie. La première étape consiste
à ajouter une nouvelle colonne à la table des commandes. Cette colonne doit accepter la valeur NULL car pour les lignes de
commande existantes, le nom de l’utilisateur Oracle est inconnu.
Modification de la table des commandes :
Table modifiée.
SQL>
Dans le trigger, le nom de la nouvelle ligne est changé, il s’exécute avant vérification des contraintes d’intégrité pour chaque
ligne insérée dans la table commandes.
Définition du trigger :
Déclencheur créé.
SQL>
On souhaite connaître le nombre de commandes saisies par utilisateur Oracle. Pour éviter d’écrire une requête qui parcourt la
totalité de la table des commandes, ce qui peut être très lourd, une table de statistiques va être alimentée par le trigger.
Création de la table de statistiques :
Table créée.
SQL>
Le trigger doit s’assurer que l’utilisateur existe dans la table des statistiques, et s’il n’est pas déjà présent alors il faut le créer.
Le trigger s’exécute après chaque insertion de ligne, pour des raisons d’optimisation en cas de violation des contraintes
d’intégrité.
Le code du trigger :
Déclencheur créé.
SQL>
L’écriture d’un déclencheur peut se compliquer lorsque certains traitements sont communs, par exemple, aux
instructions INSERT et UPDATE alors que certaines autres sont spécifiques à l’insertion ou bien à la mise à jour des
informations. Une première solution consiste à écrire 2 déclencheurs, l’un pour l’instruction INSERT et l’autre pour
l’instruction UPDATE. Il en résulte alors une certaine redondance de codage ce qui n’est jamais souhaitable
(maintenance plus lourde du code). Oracle propose les prédicats INSERTING, UPDATING et DELETING qui permettent au
sein du déclencheur de savoir si le code PL/SQL est exécuté suite à une instruction INSERT, UPDATE ou bien DELETE.
Ces prédicats retournent une valeur booléenne et ils sont utilisés dans la condition de test d’une instruction IF. Il est
ainsi possible d’écrire un déclencheur commun aux instructions INSERT et UPDATE, par exemple, tout en conservant
l’exécution conditionnelle de certaines instructions.
Exemples
Dans l’exemple suivant, le déclencheur va être commun aux instructions INSERT et DELETE afin de maintenir à jour l’attribut
CALCULE qui représente le nombre de commandes d’un client.
L’exemple suivant permet de montrer l’intérêt des déclencheurs instead of. Dans un premier temps la vue CLINANTES est
créée. Cette vue permet de connaître les clients qui habitent Nantes. Un client est ensuite inséré au travers de cette vue,
mais il ne peut pas y être retrouvé.
Création de la vue et mise en avant de la faille :
Un trigger de type INSTEAD OF va donc être défini pour pallier cette faille et pour garantir que les éléments insérés dans une
vue seront visibles au travers de cette vue.
Création du trigger et test :
Trigger INSTEAD OF associé à une VIEW sur les tables COMMANDES et LIGCDES.
SQL> create or replace view vcdelig (nocde, datecde, nolig, refart, qtecde) as
2 select l.nocde, datecde, nolig, refart, qtecde
3 from commandes c, ligcdes l
4 where c.nocde=l.nocde;
Vue créée.
Déclencheur créé.
SQL>
En version 11, Oracle a introduit la notion de trigger composé.
À la différence d’un trigger simple dont l’instant de déclenchement est unique (avant ou après l’instruction ou la mise à
jour de ligne), un trigger composé peut comporter jusqu’à quatre sections correspondant chacune à un instant de
déclenchement : avant instruction, avant chaque ligne, après chaque ligne, après instruction.
Le trigger composé présente un avantage par rapport à l’utilisation de plusieurs triggers séparés : les différentes
sections peuvent partager des déclarations communes (variables, types, curseurs, sousprogrammes, etc.).
Syntaxe
La clause FOR remplace la clause BEFORE/AFTER d’un trigger simple et permet de définir l’événement de déclenchement
du trigger.
La clause ON permet de spécifier la table concernée ; à ce niveau, la clause FOR EACH ROW du trigger simple est interdite.
Les clauses FOLLOWS, ENABLE/DISABLE et WHEN sont les mêmes que pour un trigger simple.
instant_déclenchement IS
[déclarations_locales]
BEGIN
instructions
END instant_déclenchement
La clause optionnelle déclarations_locale permet de définir des déclarations locales à la section de code.
À titre d’exemple, nous allons créer un trigger qui audite les modifications de salaire des employés :
Déclencheur créé.
Ce trigger composé définit deux déclarations communes : une variable cumul pour stocker le montant cumulé des
modifications de salaire et une procédure affiche pour afficher une information à l’écran.
Dans la section after statement, le trigger se contente d’afficher la valeur de la variable globale cumul.
Nous pouvons maintenant tester ce trigger :
NOEMP SALAIRE
---------- ----------
1 1200
2 1800
Les événements système sont l’arrêt et le démarrage de l’instance Oracle (startup et shutdown) et la gestion des
erreurs. Les triggers d’arrêt et de démarrage ont comme portée l’ensemble de l’instance Oracle, tandis que le trigger de
gestion des erreurs peut être défini soit au niveau du schéma soit au niveau de la base de données.
Au niveau de l’utilisateur, des triggers peuvent exister pour ses opérations de connexion et de déconnexion (logon et
logoff), pour surveiller et contrôler l’exécution des ordres du DDL (CREATE, ALTER et DROP) et du DML (INSERT, UPDATE
et DELETE).
Les triggers DML sont associés à une table et à un ordre du DML, leur définition et utilisation a été détaillée
précédemment dans ce chapitre.
Lors de l’écriture de ces triggers, il est possible d’utiliser des attributs pour identifier précisément l’origine de
l’événement et adapter les traitements en conséquence.
1. Les attributs
ora_client_ip_address
Permet de connaître l’adresse IP du poste client à l’origine de la connexion.
ora_database_name
Nom de la base de données.
ora_des_encrypted_password
Permet de connaître les descripitions codées du mot de passe de l’utilisateur qui vient d’être créé ou modifié.
ora_dict_obj_name
Nom de l’objet sur lequel l’opération du DDL vient d’être exécutée.
ora_dict_obj_name_list
Permet de connaître la liste de tous les noms d’objet qui ont été modifiés.
ora_dict_obj_owner
Propriétaire de l’objet sur lequel l’opération du DDL a porté.
ora_dict_obj_owner_list
Permet de connaître la liste de tous les propriétaires des objets qui ont été modifiés.
ora_dict_obj_type
Type de l’objet atteint par la dernière opération DDL.
ora_grantee
Permet de connaître les utilisateurs qui possèdent ce privilège.
ora_instance_num
Numéro de l’instance.
Retourne Vrai si la colonne passée en paramètre a été modifiée.
ora_is_creating_nested_table
Permet de savoir si une table de fusion a été créée.
ora_is_drop_column
Permet de savoir si la colonne passée en paramètre a été modifiée.
ora_is_servererror
Retourne Vrai si le numéro de l’erreur passée en paramètre se trouve dans la pile des erreurs.
ora_login_user
Permet de connaître le nom de connexion.
ora_privileges
Permet de connaître la liste des privilèges accordés ou retirés par un utilisateur particulier.
ora_revokee
Permet de connaître les utilisateurs à qui le privilège a été enlevé.
ora_server_error
Retourne le numéro de l’erreur Oracle dans la pile dont la position lui est passée en paramètre (le sommet de la pile
occupe la position 1).
ora_sysevent
Nom de l’événement système qui a déclenché le trigger.
ora_with_grant_option
Retourne Vrai si le privilège a été accordé avec une option d’administration.
2. Les événements système
STARTUP
L’événement est déclenché lors de l’ouverture de l’instance.
SHUTDOWN
L’événement est déclenché juste avant que le serveur ne commence le processus d’arrêt de l’instance. Lors d’un arrêt
brutal du serveur de base de données, cet événement ne sera pas exécuté.
SERVERERROR
L’événement est déclenché lorsqu’une erreur Oracle se produit. Cependant, ce trigger n’est pas déclenché pour les
erreurs ORA1034, ORA1403, ORA1422, ORA1423 et ORA4030 qui sont trop importantes pour que le processus
puisse continuer à s’exécuter.
Syntaxe
Exemple
Mise en place d’un trigger de gestion des erreurs : dans l’exemple ciaprès, les informations concernant chaque erreur
provoquée sur le schéma de l’utilisateur qui crée le trigger sont enregistrées dans la table les_erreurs qui a été créée au
préalable.
3. Les événements utilisateur
AFTER LOGON
Après avoir établi une connexion avec le serveur.
BEFORE LOGOFF
Avant de rompre la connexion avec le serveur.
BEFORE CREATE, AFTER CREATE
Lorsqu’un objet est créé.
BEFORE ALTER, AFTER ALTER
Lorsqu’un objet est modifié.
BEFORE DROP, AFTER DROP
Lorsqu’un objet est supprimé.
BEFORE ANALYZE, AFTER ANALYZE
Quand un ordre d’analyse est exécuté.
BEFORE ASSOCIATE STATISTICS AFTER ASSOCIATE STATISTICS
Quand une association de statistiques est exécutée.
BEFORE AUDIT, AFTER AUDIT
Lorsqu’un audit est mis en place.
BEFORE NOAUDIT, AFTER NOAUDIT
Lorsqu’une opération d’audit est annulée.
BEFORE COMMENT, AFTER COMMENT
BEFORE DDL, AFTER DDL
Lors de l’exécution de la plupart des ordres du DDL à l’exception des commandes ALTER DATABASE, CREATE
CONTROLFILE, CREATE DATABASE ainsi que toutes les commandes du DDL issues d’un bloc PL/SQL.
BEFORE DISSOCIATE STATISTICS AFTER DISSOCIATE STATISTICS
Lors de la dissociation des statistiques d’un objet.
BEFORE GRANT, AFTER GRANT
Lors de l’exécution de la commande GRANT.
BEFORE RENAME, AFTER RENAME
Lors de l’exécution de la commande RENAME.
BEFORE REVOKE, AFTER REVOKE
Lors de l’exécution de la commande REVOKE.
BEFORE TRUNCATE, AFTER TRUNCATE
Lors de la troncature d’une table.
Syntaxe
Il faut consulter la liste cidessus pour savoir si l’événement peut être traité en BEFORE et ou en AFTER.
Exemple
Mise en place d’un trigger de surveillance des tables : dans l’exemple suivant, le trigger mis en place permet de scruter
toutes les créations de table. Tous les renseignements sont stockés dans la table INFOS_TABLE qui a été créée auparavant.
Exemple
Désactivation puis réactivation de triggers :
Pour obtenir des informations sur les triggers il faut interroger le dictionnaire de données. Les trois vues du dictionnaire
à utiliser sont : USER_TRIGGERS, ALL_TRIGGERS et DBA_TRIGGERS.
La colonne BASE_OBJECT_TYPE permet de savoir si le trigger est basé sur une table, une vue, un schéma ou la totalité
de la base de données.
La colonne TRIGGER_TYPE permet de savoir s’il s’agit d’un trigger BEFORE, AFTER ou INSTEAD OF, si son mode
d’exécution est FOR EACH ROW ou non, s’il s’agit d’un trigger événementiel ou non.
La colonne TRIGGERING_EVENT permet de connaître quel événement est concerné par le trigger.
Exemple
Interrogation du dictionnaire : dans l’exemple suivant, la vue USER_TRIGGERS est interrogée pour connaître les déclencheurs
posés sur le schéma de l’utilisateur courant.
OR REPLACE
Remplace la description si la procédure existe.
paramètre
Variable passée en paramètre, utilisable dans le bloc.
IN
Le paramètre est passé en entrée de procédure.
OUT
Le paramètre est valorisé dans la procédure et renvoyé à l’environnement appelant.
type
Type de variable (SQL ou PL/SQL).
Exemple
Procédure de suppression d’un article :
Procédure créée.
SQL>
Utilisation par SQL*Plus :
Utilisation dans un bloc PL/SQL.
DECLARE
x char ;
BEGIN
...
supp_art (x) ;
...
END ;
Syntaxe
OR REPLACE
La description est remplacée si la fonction existe.
Paramètre
Paramètre passé en entrée utilisé comme une variable dans le bloc.
type
Type du paramètre (SQL ou PL/SQL).
RETURN type
Type de la valeur retournée par la fonction.
Exemple
Fonction factorielle :
Utilisation par SQL*Plus :
Depuis la version 11, il est possible d’indiquer à Oracle de conserver en mémoire le résultat de l’appel d’une fonction.
Lorsque cette fonctionnalité est activée pour une fonction, à chaque fois que celleci est appelée avec des valeurs
différentes des paramètres, Oracle stocke en cache la valeur des paramètres et le résultat de la fonction. Lorsque
cette fonction est de nouveau appelée ultérieurement avec les mêmes valeurs de paramètres, le résultat est retourné
à partir du cache au lieu d’être recalculé.
Pour activer cette fonctionnalité pour une fonction, il suffit d’inclure la clause RESULT_CACHE dans la définition de la
fonction.
Syntaxe
La clause optionnelle RELIES_ON permet de spécifier une ou plusieurs tables ou vues dont la fonction dépend. Lorsque
les données sont modifiées dans les tables concernées, le cache est invalidé puis reconstitué lors des appels ultérieurs
de la fonction.
Exemple
Fonction créée.
VALEUR_PARAMETRE(1)
-------------------------------------------
ENI
VALEUR_PARAMETRE(1)
-------------------------------------------
ENI
1 ligne créée.
Validation effectuée.
VALEUR_PARAMETRE(1)
-------------------------------------------
ENI
VALEUR_PARAMETRE(1)
-------------------------------------------
ENI
Lors du premier appel avec 1 comme valeur du paramètre, la fonction retourne le résultat en un peu plus de 1,5
secondes. Lors du deuxième appel avec la même valeur du paramètre, la fonction ne met plus que 15 centièmes de
seconde pour s’exécuter. Après modification des données de la table, un nouvel appel avec 1 comme valeur du
paramètre s’exécute de nouveau en un peu plus de 1,5 secondes : le cache de résultat a été invalidé car la fonction
dépend de la table modifiée (clause RELIES_ON).
Les packages se divisent en deux parties : un entête ou spécification et un corps (body). La partie spécification permet
de décrire le contenu du package, de connaître le nom et les paramètres d’appel des fonctions et des procédures. Mais
le code n’est pas présent dans la spécification. On trouve le code dans la partie body du package. Cette séparation
des spécifications et du code permet de déployer un package sans que l’utilisateur puisse visualiser le code et permet
de plus de faire évoluer simplement le code pour répondre à de nouvelles règles.
Les packages offrent de nombreux avantages :
Modularité
Le fait de regrouper logiquement les éléments PL/SQL liés rend plus facile la compréhension des différents éléments du
package et leur utilisation en est simplifiée.
Simplification du développement
Lors de la mise en place d’une application, il est possible dans un premier temps de définir uniquement la partie
spécification des packages et réaliser ainsi les compilations. Le corps du package ne sera nécessaire que pour
l’exécution de l’application.
Informations cachées
Avec un package, il est possible de rendre certains éléments invisibles à l’utilisateur du package. Cela permet de
construire des éléments qui ne peuvent être utilisés qu’à l’intérieur du package et donc l’écriture du package s’en
trouve simplifiée.
Ajout de fonctionnalités
Les variables et curseurs publics du package existent durant la totalité de la session, donc, il est possible par cet
intermédiaire de partager des informations entre les différents sousprogrammes d’une même session.
Amélioration des performances
Le package est présent en mémoire dès le premier appel à un élément qui le compose. L’accès aux différents éléments
du package est donc beaucoup plus rapide que l’appel à des fonctions et à des procédures indépendantes.
1. Entête
La portée de tous les éléments définis dans la spécification du package est globale pour le package et locale pour le
schéma de l’utilisateur.
La spécification permet de préciser quelles seront les ressources du package utilisable par les applications. Toutes les
informations pour savoir comment utiliser les ressources du package (paramètres d’appel, type de la valeur
renvoyée) doivent être présentes dans cette spécification.
Syntaxe
Exemple
Entête d’un package de gestion des clients :
Package créé.
SQL>
2. Corps du package
Le corps du PACKAGE contient l’implémentation des procédures et fonctions exposées dans la partie entête. Il
contient également des définitions de types et des déclarations de variables dont les portées sont limitées au corps
du PACKAGE.
La spécification du corps du PACKAGE n’est pas nécessaire si l’entête du PACKAGE ne comporte que des
définitions de types et des déclarations de variables.
Pour s’assurer que dans le corps du package tous les éléments précisés dans la spécification sont bien définis,
PL/SQL effectue une comparaison point par point. Aussi, à l’exception des espaces, la déclaration faite dans la
spécification doit trouver son équivalent exact dans le corps. Si ce n’est pas le cas, une exception est levée lors de la
compilation.
Le corps du package peut en plus contenir des définitions locales de curseurs, variables, types, fonctions et
procédures pour une utilisation à l’intérieur du package. Ces élément ne seront pas accessibles en dehors du
package.
Syntaxe
Exemple
Corps du package de gestion des clients :
SQL>
3. Utilisation
Les éléments d’un package (variables, procédures, fonctions) sont référencés par rapport au nom du PACKAGE à
l’aide de l’opérateur ".".
Exemple
Utilisation du package de gestion des clients :
SQL> begin
2 :V_NOCLI := GESTION_CLIENTS.CRE_CLI
3 (’CESAR’, ’Vieux Port’, 13000, ’MARSEILLE’);
4 end;
5 /
V_NOCLI
---------
2003
9 ligne(s) sélectionnée(s).
SQL> begin
2 GESTION_CLIENTS.SUPP_CLI(152);
3 end;
4 /
8 ligne(s) sélectionnée(s).
SQL>
4. Les curseurs
Il est possible de séparer la déclaration d’un curseur (sa spécification) de sa définition (son corps). Avec cette
technique, il devient alors possible de changer la définition du curseur sans que sa déclaration ne soit modifiée. La
déclaration du curseur dans la partie spécification du package doit respecter la syntaxe suivante :
La valeur retournée est, soit une valeur simple soit un enregistrement.
Dans le corps du package, il est maintenant obligatoire de définir la clause SELECT associée au curseur. Bien sûr, les
colonnes précisées derrière la clause SELECT et le type de données indiqué comme étant retourné dans la partie
spécification doivent correspondre exactement.
La définition des curseurs à l’intérieur du package offre plus de souplesse car il est possible de changer leur définition
sans pour autant être obligé de modifier la partie spécification du package.
Pour utiliser un curseur défini dans un package, il faut, dans un bloc PL/SQL, faire préfixer le nom du curseur par celui
du package. La notation est la même que celle mise en place pour appeler des fonctions ou des procédures définies
dans un package.
La portée d’un curseur de package n’est pas limitée au seul bloc dans lequel il est ouvert. Il est ainsi possible de
conserver le curseur ouvert pendant toute une session et de le fermer simplement lors de la déconnexion.
Un transaction autonome est une transaction indépendante qui est lancée depuis une autre transaction : la transaction
principale. Durant l’exécution de la transaction autonome, la transaction principale est suspendue.
Les transactions autonomes sont totalement indépendantes, et cette indépendance permet de construire des
applications plus modulaires. Bien sûr, les transactions autonomes présentent les mêmes caractéristiques que les
transactions régulières.
Pour définir une transaction autonome, il faut utiliser la directive de compilation (pragma) AUTONOMOUS_TRANSACTION.
Cette directive doit apparaître dans la section de déclaration des variables, des blocs PL/SQL anonymes, des fonctions,
des procédures et des triggers. En règle générale, les directives de compilation sont placées en début de la section de
déclaration des variables, ce qui facilite la relecture du programme.
Il n’est pas possible de placer la directive de compilation pragma AUTONOMOUS_TRANSACTION au niveau du
package. Par contre, chaque fonction et procédure du package peut être déclarée en tant que transaction
autonome.
Exemple
Procédure définissant une transaction autonome : dans l’exemple suivant, la fonction de mise à jour des clients constitue une
transaction autonome.
Les modifications réalisées par la transaction autonome sont visibles des autres transactions immédiatement après sa
validation (COMMIT), même si la transaction principale qui a appelé la transaction autonome n’est pas terminée. Les
modifications seront également visibles par la transaction principale. Pour que la transaction principale ne puisse pas
connaître les modifications, il faut préciser le niveau d’isolation de la transaction à l’aide de la commande suivante : SET
TRANSACTION ISOLATION LEVEL SERIALIZABLE.
Les transactions autonomes sont contrôlées par les ordres COMMIT, ROLLBACK et SAVEPOINT. À l’intérieur d’un bloc
PL/SQL défini comme transaction autonome, il est possible de réaliser plusieurs transactions les unes à la suite des
autres. Pour la transaction principale appelante, c’est l’ensemble des transactions du bloc appelé qui est autonome.
Exemple
Procédure définissant une transaction autonome : dans l’exemple ciaprès, la procédure de mise à jour des clients est appelée
depuis un bloc PL/SQL anonyme, dont la transaction est annulée. On constate que le travail de la procédure reste validé.
Il est également possible de définir les triggers comme réalisant des transactions autonomes. Cette option est
intéressante lorsque l’on utilise les triggers pour journaliser les opérations qui interviennent sur une table, même si
l’opération n’est pas validée. Le fait que le trigger soit autonome permet d’assurer que le travail réalisé sera enregistré
dans la base de données, même si l’opération à l’origine de l’exécution du trigger est annulée (ROLLBACK).
De plus, contrairement aux triggers traditionnels, les triggers autonomes peuvent exécuter des ordres SQL DDL en
utilisant des ordres SQL Dynamique.
La clause RETURNING
Dans le cas où l’instruction INSERT est utilisée pour insérer une seule ligne d’informations dans la table, il est possible
d’utiliser la clause RETURNING pour connaître par exemple la valeur d’une colonne ou bien le résultat d’un calcul. Cette
fonctionnalité s’avère particulièrement pratique lorsqu’une séquence est associée à la colonne et que la valorisation de
la colonne à partir de la séquence est réalisée depuis un déclencheur de base de données.
La clause RETURNING permet de connaître la valeur qui a été générée et insérée dans la table. Sans cette clause, les
accès à la base sont multipliés pour connaître la valeur affectée à la colonne.
Syntaxe
Exemple
Dans l’exemple suivant, une fonction de création des clients est mise en place. Cette fonction utilise une séquence oracle pour
fixer le numéro de clients. La valeur du numéro de client est retournée par la fonction.
Il est également possible d’utiliser cette clause RETURNING dans une instruction DELETE afin d’obtenir une ou plusieurs
informations sur la ligne supprimée.
Enfin il est possible d’utiliser cette clause RETURNING avec l’instruction de mise à jour UPDATE. Comme pour les instructions
INSERT et DELETE, la clause RETURNING n’est concevable que dans le cas où l’instruction UPDATE met à jour une seule ligne
d’informations dans la base.
Syntaxe
De plus, par l’intermédiaire du SQL dynamique, il devient possible d’exécuter des instructions du DDL (CREATE, ALTER,
DROP, GRANT et REVOKE) ainsi que les commandes ALTER SESSION et SET ROLE à l’intérieur du code PL/SQL, ce qui est
impossible avec le SQL statique.
Le SQL dynamique sera donc utilisé pour répondre à l’un des points suivants :
● La commande SQL n’est pas connue au moment de la compilation.
● L’ordre à exécuter n’est pas supporté par le SQL statique.
● Pour exécuter des requêtes construites lors de l’exécution.
● Pour référencer un objet de la base de données qui n’existe pas au moment de la compilation.
● Pour pouvoir optimiser la requête lors de son exécution.
● Pour créer des blocs PL/SQL de façon dynamique.
● Pour travailler sur les droits des utilisateurs de façon dynamique.
Le SQL dynamique offre de meilleures performances que le package DBMS_SQL et plus de possibilités.
1. EXECUTE IMMEDIATE
La commande EXECUTE IMMEDIATE permet de vérifier la syntaxe et d’exécuter de façon dynamique un ordre SQL ou
un bloc anonyme PL/SQL.
Syntaxe
chaîne_dynamique
représente l’ordre SQL ou le bloc PL/SQL. Depuis la version 11, la taille du code dynamique n’est plus limitée à 32 ko ;
si besoin, une variable de type CLOB peut être utilisée.
variable
est une variable qui va stocker la valeur issue d’une colonne sélectionnée.
est une variable structurée qui va contenir une ligne sélectionnée.
argument
valeurs passées à l’ordre SQL ou au bloc PL/SQL. Ces arguments peuvent représenter des valeurs en lecture/écriture.
À l’exception des requêtes qui retournent plusieurs lignes, il est possible d’exécuter n’importe quel ordre SQL ou bloc
PL/SQL. Les arguments ne peuvent pas contenir le nom d’objets de la base de données qui vont être utilisés par les
ordres SQL ou PL/SQL.
La commande INTO ne doit être utilisée que pour des requêtes SELECT ne retournant qu’une seule ligne de valeur.
Pour chaque colonne retournée par la commande SELECT, doit correspondre une variable ou bien un champ dans
l’enregistrement.
Les arguments peuvent être tous placés derrière l’instruction USING. Leur mode par défaut est alors IN, c’estàdire
qu’ils fournissent une valeur à la commande dynamique. Les arguments de type OUT peuvent être précisés derrière le
mot clé RETURN INTO ou RETURNING INTO. Les arguments peuvent contenir des valeurs de type numérique ou bien
des chaînes de caractères, mais il n’est pas possible d’y passer des valeurs booléennes (TRUE ou FALSE).
Exemple
SQL Dynamique : l’exemple ciaprès montre une utilisation possible du SQL dynamique et des différentes possibilités de
l’ordre EXECUTE IMMEDIATE.
Lorsqu’un ordre INSERT, UPDATE ou DELETE possède une clause de type RETURNING, il est possible de placer
les arguments de sortie soit dans la clause USING, soit dans la clause RETURNING INTO. Dans les nouvelles
applications, il faut utiliser la clause RETURNING INTO.
Utilisation de la clause RETURNING INTO :
En utilisant la clause USING, il n’est pas nécessaire de préciser le mode d’utilisation pour les paramètres entrants car
le mode par défaut est IN. Avec la clause RETURNING INTO, on ne peut pas préciser le mode d’utilisation du paramètre,
c’est obligatoirement OUT. Lorsque cela est nécessaire, il faut spécifier le mode d’utilisation des paramètres en OUT ou
IN OUT, par exemple lors de l’appel d’une procédure.
Définition d’une procédure avec des paramètres en mode IN, OUT et IN OUT :
Dans l’exemple suivant, la procédure définie cidessus va être appelée de façon dynamique. Le mode d’utilisation des
différents paramètres sera précisé derrière la clause USING.
Les modes d’utilisation des paramètres :
2. OPEN FOR, FETCH et CLOSE
Ces trois commandes seront utilisées pour traiter les requêtes dynamiques qui vont ramener plusieurs lignes
d’information. Comme pour les curseurs traditionnels, dans un premier temps, il faut ouvrir le curseur à l’aide de la
commande OPEN FOR qui correspond à une requête de type SELECT. Puis toutes les lignes d’information pourront être
ramenées une par une dans le bloc PL/SQL par l’intermédiaire de la commande FETCH. Enfin, lorsque toutes les lignes
a. Ouvrir un curseur (OPEN FOR)
La commande OPEN FOR permet d’associer à une variable de type curseur une requête SELECT qui retourne
plusieurs lignes d’information. La requête est exécutée et le curseur est placé sur la première ligne d’information.
Contrairement au curseur statique, l’instruction OPEN FOR des curseurs dynamiques possède une clause USING
optionnelle afin de passer des arguments à la requête.
Syntaxe
Exemple
Dans l’exemple suivant, une variable de type curseur est déclarée, puis elle est associée à une commande SELECT qui
ramène des informations depuis une table.
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable curseur
vno clients.nocli%type;
vville clients.ville%type:=’Nantes’;
begin
open ccli for ’Select nocli, ville from clients where ville=:v’
using vville;
...
end;
/
Tous les arguments de la requête sont évalués uniquement lorsque le curseur est ouvert. Donc, pour ramener des
informations correspondant à différentes valeurs de l’argument, il faut rouvrir le curseur en lui passant une nouvelle
valeur pour le paramètre.
Depuis la version 11, la taille de la requête dynamique n’est plus limitée à 32 ko ; si besoin, une variable de type
CLOB peut être utilisée.
b. FETCH
La commande FETCH retourne une ligne de données issue du jeu de résultats correspondant à l’exécution de la
requête SELECT lors de l’ouverture du curseur. Pour chacune des colonnes précisées derrière le SELECT, il faut
prévoir une variable dans l’environnement PL/SQL qui exécute le curseur dynamique.
Syntaxe
FETCH varible_curseur
INTO {variable, ...|enregistrement}
Exemple
Il est possible de compléter l’exemple cidessus en ajoutant le code correspondant au traitement des lignes.
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable curseur
vno clients.nocli%type;
vville clients.ville%type:=’Nantes’;
begin
open ccli for ’Select nocli, ville from clients where ville=:v’
using vville;
loop
fetch ccli into vno, vville; --ramener la ligne suivante
exit when ccli%notfound; --quitter la boucle si plus de lignes
--traiter les informations
end loop;
...
end;
Il est possible d’utiliser des clauses INTO différentes sur des commandes séparées de FETCH travaillant sur
le même curseur.
Chaque exécution de la commande FETCH ramène une ligne du jeu de résultats et place le curseur sur la
ligne suivante.
Si un FETCH est exécuté sur un curseur fermé ou bien jamais ouvert, alors l’exception INVALID_CURSOR est
levée.
c. CLOSE
La commande CLOSE désactive une variable de type curseur. Après cette commande, le jeu de résultats, construit
par la commande OPEN FOR n’existe plus.
Syntaxe
CLOSE variable_curseur
Exemple
Dans cet exemple lorsque la dernière ligne a été traitée, alors le curseur est fermé :
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable curseur
vno clients.nocli%type;
vville clients.ville%type:=’Nantes’;
begin
open ccli for ’Select nocli, ville from clients where ville=:v’
using vville;
loop
fetch ccli into vno, vville; --ramener la ligne suivante
exit when ccli%notfound; --quitter la boucle si plus de lignes
--traiter les informations
end loop;
close ccli;
end;
Lors de la tentative de fermeture d’un curseur qui est déjà fermé, PL/SQL lève l’exception INVALID_CURSOR.
3. Utilisation des curseurs dynamiques
Quelques règles existent pour essayer de tirer le meilleur parti des curseurs dynamiques en terme de performances et
de qualité de programmation.
a. Amélioration des performances
Dans le code exposé cidessous, Oracle est obligé de mettre en place un nouveau curseur pour chaque nouvelle
ouverture. Cette génération de curseurs très similaires peut dégrader les performances du serveur.
L’amélioration des performances passe par l’utilisation d’un argument. Cette solution permet à Oracle de réutiliser le
même curseur pour différentes valeurs de l’argument.
b. Passer le nom d’un objet
La procédure suivante se propose de supprimer n’importe quelle table de la base de données. En utilisant le SQL
dynamique, le code suivant est saisi :
Au moment de son exécution, cette procédure lèvera une erreur du type "nom de table invalide". Ceci est dû au fait
que les arguments ne peuvent pas servir à passer des noms d’objets de la base de données. À la place de ce code,
il faudrait saisir le code suivant :
c. Utiliser plusieurs fois le même argument
Les variables qui apparaissent dans les ordres SQL dynamiques sont associées à des arguments présents derrière
la clause USING en respectant leur position et non leur nom pour les identifier à un argument. Ainsi, si la même
variable apparaît deux fois dans la commande SQL dynamique, alors le même argument devra apparaître deux fois
derrière la clause USING.
On obtient alors le code suivant :
Cependant, si on utilise un bloc PL/SQL, il n’est pas nécessaire de passer deux fois le même argument. En effet, dans
les blocs PL/SQL, les variables sont associées aux arguments en respectant leur ordre de définition bien sûr, mais, si
la même variable apparaît plusieurs fois, alors seule la première occurrence sera associée à un argument. D’où le
code suivant qui est plus simple à écrire :
d. Les attributs des curseurs
Les curseurs explicites possèdent les quatre attributs suivants : %FOUND, %NOTFOUND, %ISOPEN et %ROWCOUNT
qui permettent d’obtenir des informations concernant la bonne exécution du curseur, qu’il provienne d’un ordre SQL
statique ou dynamique. Pour mener à bien l’ensemble de ces traitements, Oracle utilise des curseurs implicites. Il est
possible de connaître les attributs de ces curseurs en utilisant le mot clé SQL. Ainsi, l’attribut %ROWCOUNT sur les
curseurs implicites va permettre de connaître le bon déroulement ou non du dernier ordre SQL dynamique qui a été
exécuté.
Exemple
Fonction utilisant l’attribut du curseur implicite pour connaître le bon déroulement de l’ordre SQL dynamique : dans
l’exemple suivant, après la suppression de lignes, l’attribut %ROWCOUNT est utilisé pour connaître le nombre de lignes
affectées par cette commande.
Il est nécessaire de tester la fonction depuis un bloc PL/SQL car il est impossible d’exécuter une fonction du
DML depuis une requête SELECT.
e. Passer des valeurs NULL
Il peut parfois être nécessaire de passer des valeurs NULL en tant qu’arguments à des ordres SQL dynamiques.
L’opération la plus naturelle serait d’écrire la commande suivante :
Comme bien souvent, la valeur NULL ne se gère pas aussi simplement. En effet, il n’est pas possible d’utiliser le
littéral NULL derrière la clause USING. Pour pouvoir contourner cette limite, l’opération consiste à initialiser une
variable avec la valeur NULL et à l’utiliser en tant que paramètre.
declare
c_null char(1); --la variable est initialisée à NULL
begin
execute immediate ’UPDATE clients set ville=:x’ using c_null;
end;
f. Utiliser les droits de l’utilisateur
Par défaut, une procédure stockée s’exécute en utilisant les droits de l’utilisateur Oracle qui définit cette procédure
et non pas en utilisant les droits de l’utilisateur qui appelle cette procédure. Certaines procédures sont liées au
schéma sur lequel elles sont définies.
Par exemple, si la procédure suivante est définie sur le schéma de l’utilisateur livre :
La procédure supprime permet de supprimer n’importe quel objet du schéma, il faut simplement passer en paramètre
le type de l’objet à supprimer et son nom. Afin de faciliter la gestion des objets dans chaque schéma, le privilège
EXECUTE a été accordé à l’utilisatrice Marie. Lorsque l’utilisatrice Marie souhaite supprimer sa table CLIENTS de son
schéma, elle fait appel à la procédure supprime de la façon suivante :
Exécution de la procédure supprime depuis le schéma de Marie :
Comme le nom d’objet est passé sans référence au schéma, c’est en fait la table Clients, située dans la schéma livre,
qui est le créateur de cette procédure que Marie tente de supprimer.
Afin de résoudre tous ces problèmes et pour garantir que la procédure stockée va être exécutée en fonction des
droits de l’utilisateur qui en fait usage et non pas de ceux de son propriétaire, il faut utiliser la clause AUTHID lors de
la définition de la procédure. Ainsi, les noms d’objets sont résolus dans le schéma de l’utilisateur de la procédure et
non pas dans celui de son propriétaire.
Redéfinition de la procédure en utilisant la clause AUTHID :
g. La directive de compilation RESTRICT_REFERENCES
Une fonction appelée depuis une commande SQL doit obéir à un certain nombre de règles pour contrôler les effets
de bords. Pour outrepasser ces contraintes, il est possible d’utiliser la directive de compilation
RESTRICT_REFERENCES. La commande pragma assure que la fonction ne va pas travailler en lecture/écriture avec
une table de la base ou une variable d’un package.
Cependant, si le corps de la fonction contient un ordre dynamique de type INSERT, UPDATE ou DELETE, alors la
fonction viole les règles de nonécriture dans la base (Write No Database State : WNDS) et de nonlecture de la base
(Read No Database State : RNDS). C’est pourquoi les règles concernant les ordres dynamiques ne sont vérifiées
qu’au moment de leur exécution. Pour un ordre EXECUTE IMMEDIATE, seule la clause INTO permet de détecter une
violation de RNDS au moment de la compilation.
h. Éviter les verrous mortels
Il n’est pas possible de supprimer tous les verrous mortels qui peuvent se produire. Néanmoins, il est possible de
prendre certaines précautions pour éviter de se bloquer soimême. Ainsi, il ne faut jamais essayer de modifier
(ALTER) ou de supprimer (DROP) un sousprogramme ou un package que l’on est en train d’utiliser, comme dans
l’exemple suivant :
4. Le package DBMS_SQL
En plus du SQL dynamique, Oracle fournit le package DBMS_SQL pour exécuter de façon dynamique des ordres SQL.
Pour utiliser le SQL dynamique la base de données doit être compatible avec la version 8.1.0 ou supérieure au
serveur de base de données.
Le package DBMS_SQL est une librairie PL/SQL afin d’autoriser l’exécution d’ordres SQL construits dynamiquement.
● la facilité d’utilisation,
● de meilleures performances d’exécution,
● le support de types de données définis par l’utilisateur.
Néanmoins, le package DBMS_SQL possède quelques avantages par rapport au SQL Dynamique :
● il est supporté par les applications clientes,
● il supporte la procédure DESCRIBE_COLUMNS qui permet de connaître les informations relatives aux colonnes
d’un curseur ouvert au travers de DBMS_SQL,
● il supporte la copie de données par blocs pour transférer les données issues d’une requête de type SELECT
vers une collection.
L’utilisation des tableaux en PL/SQL n’est pas forcément évident au premier abord. En effet, pourquoi s’obliger à utiliser
une telle structure alors que pour stocker un ensemble d’informations, il est très facile de créer une table temporaire.
La raison est très simple : en stockant l’ensemble des données sous forme de collection directement dans le bloc
PL/SQL, tous les traitements peuvent être effectués par le moteur PL/SQL. En limitant les requêtes SQL, on limite les
accès à la base, ce qui permet d’accélérer le temps de traitement du bloc PL/SQL, mais on limite également l’occupation
du moteur SQL et les requêtes des autres utilisateurs peuvent donc être traités plus rapidement.
On voit donc qu’il existe des bénéfices à travailler avec les collections même si dans un premier temps le code PL/SQL à
mettre en place est un peu plus compliqué. Il est à noter que l’instruction FORALL (vue plus loin dans ce chapitre)
permet de faciliter considérablement les étapes de codages nécessaire pour pouvoir travailler avec les collections dans
un bloc PL/SQL.
1. Référencer un élément d’une collection
Pour pouvoir travailler avec une collection, il faut d’abord savoir comment accéder à un élément d’une collection.
Toutes les références possèdent la même structure : le nom de la collection suivi d’un indice entre parenthèses.
nom_collection (indice)
L’indice doit être un nombre valide compris entre 2 31 et 2 31 .
Pour les collections de type nested table, la plage normale des indices va de 1 à 2 31 et pour les tableaux (VARRAY) elle
va de 1 à la taille maximale du tableau.
Il est possible de faire référence à un élément d’une collection partout où il est possible d’utiliser une variable PL/SQL.
Exemple
Déclaration et utilisation d’une collection :
DECLARE
TYPE liste IS TABLE OF VARCHAR2(15);
lesnoms liste:=liste(’B Martin’,’MP Macraigne’,’S Guegan’,’
T Groussard’);
i BINARY_INTEGER;
BEGIN
...
IF lesnoms(i) =’G Viaud’ THEN
...
END IF;
...
END;
Lorsqu’une fonction retourne une collection, il est possible de faire référence à un élément de la collection en
utilisant la syntaxe suivante : nom_fonction(paramètre)(indice)
2. Assigner une valeur et comparer des collections
Il est possible d’assigner une collection à une autre à condition qu’elles soient toutes les deux de même type.
L’assignation peut être réalisée par l’opérateur :=, les commandes INSERT, UPDATE, FETCH et SELECT ou par l’appel
d’un sousprogramme.
De plus, il est important de respecter certaines contraintes comme l’illustre l’exemple suivant :
DECLARE
TYPE Clientele IS VARRAY(100) OF Client ;
TYPE Fidele IS VARRAY(100) OF Client ;
grp1 Clientele :=Clientele(...) ;
Si on assigne la collection NULL à une autre collection, alors cette seconde devient NULL et il faudra la réinitialiser.
Il est possible d’assigner une valeur précise à un élément d’une collection en utilisant la syntaxe suivante :
nom_collection(indice) :=expression
L’expression contient une valeur de même type que la collection.
Si l’indice est NULL ou si ce n’est pas un entier, alors PL/SQL lève l’exception VALUE_ERROR.
Lorsque l’on tente d’accéder à un élément en dehors de la collection, alors PL/SQL lève l’exception
SUBSCRIPT_BEYOND_COUNT.
Si l’on tente d’accéder à un élément d’une collection NULL alors PL/SQL lève l’exception COLLECTION_IS_NULL.
L’exemple suivant illustre les différents cas dans lesquels peuvent être levées les exceptions énumérées cidessus.
DECLARE
TYPE tableau IS TABLE OF INTEGER ;
montab tableau ;
BEGIN
montab(1) :=5 ;-- exception COLLECTION_Is_NULL
montab :=tableau(10,5,3,6) ;
montab(1) :=length(’Hello’) ;
montab(2) :=montab(3)*2 ;
montab(’H’) :=10 ;-- exception VALUE_ERROR
montab(10) :=1 ;--exception SUBSCRIPT_BEYOND_COUNT ;
END ;
Les collections de type nested table et varray sont automatiquement assignées à NULL lors de leur déclaration. Il est
donc possible de tester leur nullité.
DECLARE
TYPE tableau IS TABLE OF INTEGER ;
montab tableau ;
BEGIN
...
IF montab IS NULL THEN
...
END IF ;
...
END ;
Toutefois, les collections ne peuvent pas être comparées globalement à l’idée d’une égalité (=) ou d’une inégalité (<,>,
<=, >=, <>). Par exemple, le test de l’instruction If ciaprès pose une erreur de compilation.
DECLARE
TYPE tableau IS TABLE OF INTEGER ;
montab tableau :=tableau(5,6,7) ;
montab2 tableau :=tableau(1,2,3) ;
BEGIN
...
-- la ligne suivante provoque une erreur de compilation
IF montab=montab2 THEN
...
END IF ;
...
END ;
Cette limitation est levée depuis la version 10 pour les collections de type nested table (voir plus loin).
3. Travailler avec les collections
a. Travailler avec les collections de type NESTED TABLE
À l’aide de SQL*Plus, définissons le type Typestock :
Il faut ensuite définir le type Tabstock comme étant une collection d’éléments de type Typestock.
Définition du tableau tabstock :
Il est maintenant possible de définir la table Depot de la façon suivante :
Chaque élément présent dans la colonne stock est une collection de type nested table, qui va permettre de
conserver le stock de chaque dépôt. La clause NESTED TABLE est nécessaire lors de la création de la table Depot car
la colonne stock est une collection.
Ajout de données dans la table à l’aide de la commande INSERT : il est possible d’insérer des valeurs dans cette table
Depot de la façon suivante :
La modification des données de la table Depot est également possible par l’intermédiaire d’une clause UPDATE :
Afin de rendre le travail avec les collections encore plus facile, il est possible de s’appuyer sur l’instruction %ROWTYPE pour
définir une collection qui possède exactement la même structure qu’une table.
Dans l’exemple cidessus une collection de type identique à la table des clients est déclarée.
b. Travailler avec les tableaux
Il est également possible de définir des colonnes basées sur un tableau à l’intérieur d’une table. Pour illustrer ce cas
de figure, la table Facture va être créée. Chaque facture correspond à un seul client, et une facture peut être établie
pour plusieurs commandes. Le numéro et le montant de chaque commande présents sur la facture sont enregistrés
dans une colonne de type tableau.
La première étape consiste à construire un type, composé du numéro de commande et du montant de la commande.
Création du type LaCommande :
Ensuite, le type correspondant à un tableau de 50 commandes (numéro et montant) est créé.
Création du type TabCommandes :
Enfin, la table Facture est mise en place.
Création de la table Facture :
Pour travailler avec les colonnes de type tableau, il est bien sûr possible d’utiliser les ordres SQL INSERT et UPDATE
comme illustré dans l’exemple ciaprès.
Exemple d’utilisation des ordres INSERT et UPDATE :
4. Manipuler les éléments des collections
Jusqu’à maintenant les instructions montrées permettent simplement de manipuler des collections dans leur globalité,
mais rien ne permet de manipuler un élément précis d’une collection.
Pour réaliser ces opérations à l’aide du langage SQL, il faut utiliser la clause TABLE dont la sousrequête retourne une
seule colonne dont on va manipuler les données à l’aide des opérations SQL classiques. Dans l’exemple ciaprès, une
ligne d’informations est ajoutée à la collection stock dans la table dépôt puis la collection Lescommandes de la table
Facture est interrogée pour connaître le montant total d’une facture.
Manipuler une ligne de la collection :
Il est également possible de définir des collections non pas dans des tables mais localement dans un bloc PL/SQL,
pour faciliter la manipulation et le traitement des données à l’intérieur de ce bloc. Même si la logique de manipulation
des collections reste la même, il faut utiliser le mot réservé CAST afin de convertir la collection locale en un type bien
précis. Dans l’exemple suivant, le but est de comparer deux collections, l’une est définie localement dans le bloc
PL/SQL et l’autre provient d’une table. La valeur retournée correspond au nombre d’écarts entre les deux collections.
Manipuler une collection définie dans le bloc PL/SQL :
5. Les méthodes
Il existe un certain nombre de méthodes qui facilitent le travail avec les collections. Les méthodes sont des fonctions
ou des procédures qui travaillent uniquement sur les collections et dont l’appel s’effectue en préfixant le nom de la
méthode par le nom de la collection.
Syntaxe
nom_collection.nom_methode[(paramètre, ...)]
Les méthodes ne peuvent pas être utilisées à l’intérieur de commandes SQL.
Seule la méthode EXISTS peut être utilisée sur une collection NULL. L’utilisation de n’importe quelle autre
méthode sur une collection NULL provoque la levée de l’exception COLLECTION_IS_NULL.
a. EXISTS
Cette méthode accepte en paramètre l’indice de la collection dont on cherche l’existence. Ainsi nom_collection.EXISTS
Lorsque l’on teste l’existence d’un élément en dehors de la collection, alors la méthode EXISTS retourne
FALSE au lieu de lever l’exception SUBSCRIPT_OUTSIDE_LIMIT.
IF MesCommandes.EXISTS(5) THEN
MesCommandes(5):=nouvelle_commande;
END IF
b. COUNT
La méthode COUNT permet de connaître le nombre d’éléments présents dans la collection. Il est fréquent d’utiliser
cette méthode, car le nombre d’éléments contenus dans une collection n’est pas connu a priori, par exemple lorsque
la collection est stockée dans la base Oracle.
Attention, dans le cas où l’on applique cette méthode sur une collection de type NESTED TABLE, le nombre
d’éléments peut être inférieur à l’indice du plus grand élément, car les collections de ce type acceptent des éléments
NULL suite à des suppressions. Avant d’accéder à un élément il faudra donc tester son existence à l’aide de EXISTS.
parcours:=1;
i:=1
WHILE(i<MesCommandes.COUNT) LOOP
IF MesCommandes.EXISTS(parcours) THEN
...
i:=i+1;
END IF;
parcours:=parcours+1
END LOOP;
c. LIMIT
Pour les collections de type NESTED TABLE, qui n’ont pas de nombre maximum d’éléments, cette méthode retourne
NULL. Pour les collections de type VARRAYS, la méthode LIMIT permet de connaître le nombre maximum d’éléments
possibles dans la collection.
Par exemple, le type TabCommandes est une collection de 50 élements de type LaCommande, donc, si une collection
est définie de type TabCommandes, il est possible d’écrire le code suivant :
i:=1
FOR parcours IN 1 .. MesCommandes.LIMIT LOOP
WHILE(i<MesCommandes.COUNT) LOOP
IF MesCommandes.EXISTS(parcours) THEN
...
i:=i+1;
END IF;
END LOOP;
END LOOP;
d. FIRST, LAST
Les méthodes FIRST et LAST permettent de connaître le plus petit indice de la collection ainsi que le plus grand. Si la
collection est vide, alors les méthodes FIRST et LAST retournent la valeur NULL. Bien sûr, si l’indice retourné par ces
deux méthodes est le même, cela signifie que la collection ne contient qu’un seul élément.
Pour une collection de type VARRAY, la méthode FIRST retourne toujours 1 et la valeur retournée par LAST
est la même que celle retournée par COUNT.
e. PRIOR, NEXT
La méthode PRIOR(i) permet de connaître l’indice de l’élément précédant l’élément d’indice i dans la collection. La
i:=MesCommandes.FIRST;
WHILE (i IS NOT NULL) LOOP
...
i:=MesCommandes.NEXT(i);
END LOOP;
f. EXTEND
Il est possible de modifier la taille d’une collection, en l’agrandissant, par l’intermédiaire de la méthode EXTEND.
Cette méthode possède trois formes différentes d’appel :
MaCollection.EXTEND
un élément NULL est ajouté à la collection.
MaCollection.EXTEND(n)
n éléments NULL sont ajoutés à la collection.
MaCollection.EXTEND(n,i)
n éléments sont ajoutés à la collection. Chaque élément contient une copie des valeurs contenues dans l’élément
d’indice i.
Exemple d’utilisation de EXTEND :
g. TRIM
Cette méthode, qui permet de supprimer un ou plusieurs éléments à la fin de la collection, peut être utilisée sous les
deux formes suivantes :
MaCollection.TRIM
Le dernier élément de la collection est supprimé.
MaCollection.TRIM(n)
Les n derniers éléments de la collection sont supprimés.
Exemple
h. DELETE
Cette méthode, qui possède trois formes d’appels, permet de supprimer un élément, plusieurs éléments ou la
totalité d’une collection.
MaCollection.DELETE
Supprime tous les éléments de la collection.
MaCollection.DELETE(n)
Supprime l’élément numéro n de la collection.
MaCollection.DELETE(n,m)
Supprime tous les éléments dont les indices sont compris entre n et m. Les indices numéros n et m sont inclus. Si n
est plus grand que m, alors aucun élément n’est supprimé.
Dans les collections de type VARRAY, il n’est pas possible de supprimer des éléments à l’intérieur de la
collection. La seule possibilité est de supprimer le dernier élément.
Si un élément à supprimer n’existe pas, alors la méthode DELETE saute simplement cet élément. Aucune erreur n’est
levée.
PL/SQL conserve l’espace mémoire des éléments supprimés, il est donc possible de les remplacer en assignant
simplement une nouvelle valeur.
Exemple d’utilisation de DELETE :
i. COLLECT
Cette fonction de calcul d’agrégat permet d’extraire les données d’une colonne et de stocker le résultat sous forme
Pour avoir la possibilité de travailler avec le résultat de cette fonction, il est nécessaire d’inclure la fonction
COLLECT comme paramètre de la fonction CAST.
Création du tableau destiné à être alimenté par COLLECT :
Valorisation du tableau par la fonction COLLECT :
6. Les exceptions
Dans la plupart des cas, lorsque l’on tente d’accéder à un élément qui n’existe pas dans une collection, PL/SQL lève
une exception prédéfinie. Il est intéressant de citer les principales exceptions qui peuvent être levées :
COLLECTION_IS_NULL
La collection n’est pas initialisée.
NO_DATA_FOUND
L’élément accédé n’existe plus.
SUBSCRIPT_BEYOND_COUNT
L’indice de l’élément accédé a été supprimé.
SUBSCRIPT_OUTSIDE_LIMIT
L’indice est en dehors des valeurs autorisées.
VALUE_ERROR
L’indice est NULL ou n’est pas convertible en un entier.
L’exemple suivant illustre la levée de ces exceptions par PL/SQL.
DECLARE
TYPE LaListe IS TABLE OF VARCHAR2(50);
LesCourses LaListe; -- initialisé à NULL
BEGIN
LesCourses(1):=’Carotte’;-- exception COLLECTION_IS_NULL
LesCourses:=LaListe(’Tomates’,’Melon’,’Salade’);--initialise
la collection
LesCourses(NULL):=’Pommes’;-- exception VALUE_ERROR
Répartition du travail entre les deux moteurs :
Avec les copies par blocs, les ordres SQL vont pouvoir concerner toute la collection et non seulement les éléments les
uns après les autres.
L’exemple suivant, qui concerne l’insertion de lignes dans une table, permet de comparer le gain de temps entre le
traitement classique des ordres SQL dans les blocs PL/SQL et le traitement par blocs.
Création de la table Composants :
La table créée cidessus va être remplie par l’intermédiaire d’un bloc PL/SQL. Pour chacune des deux méthodes
d’insertion, le temps d’exécution sera mesuré.
Les avantages du traitement par blocs :
Pour traiter tous les éléments d’une collection, il faut utiliser le mot clé FORALL. Son utilisation est détaillée
ultérieurement.
L’utilisation du package DBMS_OUTPUT est traité plus loin dans cet ouvrage. Pour pouvoir exécuter ce script
correctement, il faut commencer par positionner la variable d’environnement SERVEROUTPUT à On dans
SQL*Plus par l’intermédiaire de la commande : SET SERVEROUTPUT ON.
1. FORALL
Dans l’écran cidessous, on retrouve différents cas d’utilisation de la commande FORALL.
Les copies d’informations par blocs peuvent être effectuées directement dans des collections d’enregistrement. Cette
fonctionnalité est offerte à partir d’Oracle 9i. Elle permet de gagner en souplesse au niveau de l’utilisation des
données dans un bloc PL/SQL.
L’exemple suivant montre différentes utilisations possibles du travail avec les collections d’enregistrements et plus
particulièrement la mise en place de la collection avec des données issues de la base avec les commandes FOR..IN et
FORALL.
declare
type tableauRec is table of table1%rowtype;
type tableauNumerique is table of number;
type tableauCaracteres is table of char(30);
cursor ctable2 is select col1, col2 from table2;
tabrec tableauRec;
tabnum tableauNumerique:=tableauNumerique(2,3,5);
tabCar tableauCaracteres:=tableauCaracteres(’Godel’,’Escher’,’Bach’);
begin
-- ajouter des données dans la table1
forall i in 1..3
insert into table1 values (tabnum(i), tabcar(i));
-- ajouter des données dans le tableau des enregistrements
select col1, col2 bulk collect into tabrec from table1;
-- utilisation du curseur
open ctable2;
fetch ctable2 bulk collect into tabrec;
close ctable2;
end;
/
select * from table1;
select * from table2;
drop table table1;
drop table table2;
a. Limitations
● Les commandes INSERT, UPDATE ou DELETE doivent faire référence à au moins une collection pour pouvoir
bénéficier de la commande FORALL.
● Il doit exister des éléments dans la collection, pour toutes les valeurs d’indice précisées dans la commande
FORALL.
● Il n’est pas possible d’exprimer l’indice sous forme d’un calcul.
b. Les transactions et la commande FORALL
À l’intérieur d’une commande FORALL, si l’une des commandes SQL provoque une erreur d’exécution, c’est alors la
totalité des instructions réalisées à l’intérieur de la commande FORALL qui est annulée (ROLLBACK).
Cependant, si l’exception qui est levée par un ordre SQL est traitée dans le bloc PL/SQL, alors les opérations
réalisées par la commande FORALL sont annulées jusqu’à un point de transaction (SAVEPOINT) qui est marqué de
façon implicite après chaque commande SQL. C’estàdire que seule la commande SQL qui est à l’origine de
l’exception est annulée de façon automatique. C’est dans le code de traitement de l’exception qu’il faudra décider, si
l’on conserve les modifications déjà effectuées (COMMIT) ou si l’on annule toute l’instruction FORALL (ROLLBACK).
c. Les clauses INDICES OF et VALUES OF
Le parcours des listes n’est pas toujours aussi facile que dans l’exemple précédent.
Pour pouvoir parcourir une liste sans avoir à tenir compte de l’indice du premier et du dernier élément, il est possible
d’utiliser la clause INDICES OF. Cette clause s’avère d’autant plus intéressante que l’on va retrouver uniquement les
éléments de la collection même s’il existe des emplacements non valorisés. La clause INDICES OF permet de garantir
le parcours complet de la collection sans qu’une exception ne soit levée.
Au contraire, si l’on souhaite parcourir simplement un sousensemble d’une collection alors il est nécessaire d’utiliser
la clause VALUES OF. Cette clause permet de récupérer les indices depuis une autre collection qui doit être de type
NESTED TABLE ou bien un tableau associé à un index numérique. Cette collection est donc une collection de
parcours.
2. L’attribut %BULK_ROWCOUNT
Lors de l’exécution des ordres SQL, un curseur est ouvert implicitement par le moteur. Il est possible de tester les
attributs %FOUND, %ISOPEN, %NOTFOUND et %ROWCOUNT, pour s’assurer du bon déroulement de la commande
SQL.
Le curseur implicite (SQL) possède un attribut supplémentaire : %BULK_ROWCOUNT, qui est utilisé avec une
commande FORALL. Cet attribut est en fait une collection de type index by table, pour lequel l’élément numéro i
contient le nombre de lignes affectées par l’exécution de l’ordre SQL numéro i. Si aucune ligne n’a été affectée par
l’instruction numéro i alors l’attribut SQL%BULK_ROWCOUNT(i) retourne la valeur 0.
Exemple d’utilisation de l’attribut %BULK_ROWCOUNT :
3. BULK COLLECT
Le mot clé BULK COLLECT indique au moteur SQL que les données seront retournées dans une collection, avant de
retourner dans le moteur PL/SQL. Il est possible d’utiliser cette commande avec les clauses SELECT INTO, FETCH INTO
et RETURNING INTO.
Syntaxe
Exemple
Utilisation de BULK COLLECT : dans l’exemple suivant, les informations extraites depuis la table clients sont conservées
dans la collection les Clients.
Il est bien sûr possible de réaliser le même genre d’opération avec un curseur.
Les gains de temps d’exécution des blocs PL/SQL sont spectaculaires pour les volumes de données importants, si l’on
travaille avec les collections. Il est facile de ramener les données depuis la table par l’intermédiaire de l’instruction
BULK COLLECT. Puis, le traitement des données est effectué directement dans la collection et enfin les modifications
sont propagées dans la table en utilisant l’instruction FORALL pour parcourir la collection.
4. LIMIT
La clause optionnelle LIMIT qui est limitée à la copie par blocs depuis un curseur, permet de limiter le nombre de lignes
d’informations ramenées lors de chaque FETCH.
Syntaxe
Le nombre de lignes doit être un nombre entier.
5. Comparer les collections
Le travail avec une collection est relativement aisé. Mais très rapidement, il va être nécessaire de travailler avec deux
ou plusieurs collections afin de comparer leurs contenus. Avant la version 10g d’oracle, pour pouvoir réaliser ce type
de travail, il était nécessaire d’écrire ses propres fonctions de comparaisons. Ce travail, en plus d’être rébarbatif,
représente l’inconvénient que la solution optimale est rarement trouvée rapidement, surtout que les parcours de liste
et les tests de comparaisons sont des sources d’erreurs communes même pour les programmeurs chevronnés. En
introduisant des instructions permettant de travailler avec les collections comme avec des ensembles, Oracle facilite le
travail avec ce type de structure.
Les instructions introduites sont : MULTISET UNION, MULTISET UNION DISTINCT, MULTISET INTERSECT, MULTISET
EXCEPT et SET. Ces instructions représentent les opérateurs disponibles sur les ensembles pour effectuer l’union,
l’intersection, la différence et extraire les éléments distincts.
Pour illustrer le fonctionnement de chacune de ces instructions et comprendre ainsi leur intérêt, on va travailler sur un
petit exemple.
Exemples
Un package pkg_test va être créé. Ce package va contenir deux collections et une procédure qui permet d’afficher le
contenu de la collection passée en paramètre.
La première étape consiste à définir le type qui va servir de base à la collection.
Ensuite, il est nécessaire de définir l’entête du package.
Puis, il faut définir le corps du package afin de donner la définition de la procédure affiche. Cette procédure correspond à un
simple parcours de collection en demandant l’affichage de chacune des valeurs.
Maintenant que la base est posée, il est possible d’illustrer les instructions.
Par exemple pour connaître l’ensemble de nos amis il est nécessaire de réaliser une union entre les deux collections.
Pour cela, on dispose des instructions MULTISET UNION et MULTISET UNION DISTINCT. La distinction entre ces 2
instructions provient du fait que la première, MULTISET UNION, va retourner l’ensemble des valeurs contenues dans
les deux collections sans chercher à éliminer les doublons tandis que la seconde, MULTISET UNION DISTINCT, va
permettre d’éliminer les doublons dans la collection résultante.
L’exemple ciaprès illustre le résultat de l’exécution de l’instruction MULTISET UNION. On remarque que Dupont apparaît
deux fois, en première et en quatrième position.
Au contraire, avec l’instruction MULTISET UNION DISTINCT, les doublons sont éliminés.
Cette fonctionnalité est illustrée par l’exemple cidessous dans lequel le nom Dupont n’apparaît qu’une seule fois.
Pour connaître les éléments communs aux deux collections, il faut utiliser MULTISET INTERSECT afin de définir la collection
d’intersection.
L’exemple cidessus permet d’obtenir la liste des amis communs.
Pour pouvoir faire la différence entre deux collections, il va être nécessaire d’utiliser l’instruction MULTISET EXCEPT.
L’exemple cidessus permet de connaître parmi la collection mesAmis ceux qui ne sont pas connus par l’autre collection
(sesAmis).
Il est bien sûr évident que pour cette instruction l’ordre, dans lequel les collections sont introduites par rapport à
l’instruction, possède une influence directe sur le résultat.
Enfin, lorsque l’on travaille avec des collections de grande importance, il est possible d’éliminer les doublons en
produisant une nouvelle collection par l’intermédiaire de l’instruction SET.
La collection résultant de l’union des deux collections initiales possède des doublons. La collection résultante produite
par l’instruction SET ne possède quant à elle aucune redondance.
Afin d’améliorer les temps de réponses de ces fonctions qui retournent un ensemble de données, l’instruction pipelined
précise que les données vont être retournées au fur et à mesure de l’exécution de la fonction. C’est d’ailleurs avec ce
type de fonction que la gestion des ensembles de valeurs renvoyées est la plus simple.
Lors de la déclaration de la fonction, le mot clé PIPELINED est ajouté dans l’entête et les informations sont retournées à
l’aide de la commande PIPE ROW.
Ces fonctions peuvent accepter en paramètre d’entrée un ensemble de lignes sous la forme d’une collection (comme un
tableau de type VARRAY) ou bien sous la forme d’un REF CURSOR (référence à un curseur).
Exemple
L’exemple suivant montre la mise en place d’une fonction qui retourne une collection de chiffres en mode pipelined c’estàdire
au fur et à mesure de l’exécution de la fonction.
Type créé.
Type créé.
Fonction créée.
TOTAL
----------
750
Wrap va donc permettre de masquer l’algorithme utilisé mais en aucun cas les chaînes de caractères, les nombres, le
nom des variables, des colonnes et des tables ne sont codés. L’utilitaire ne permet donc pas de masquer les mots de
passe ou bien les noms des tables.
Cet utilitaire est entièrement compatible avec Oracle. La compatibilité descendante n’est pas assurée.
Cet utilitaire accepte deux paramètres :
iname
Permet de préciser le fichier qui contient le code PL/SQL qui va être codé.
oname (optionnel)
Permet de spécifier le nom du fichier qui va contenir la version codée du fichier précisé à l’aide de iname. Par défaut, ce
fichier de sortie porte l’extension plb.
Syntaxe
Exemple d’utilisation de l’utilitaire Wrap
Quelques éléments de la nouvelle syntaxe SQL ne sont pas supportés en standard. Pour que tous les
éléments de la nouvelle syntaxe soit supportés, il faut utiliser le paramètre edebug=wrap_new_sql.
Si la récupération et l’affichage des informations placées dans le tampon ne sont pas gérés et si l’exécution
ne se déroule pas sous SQL*Plus, alors les informations sont ignorées. Le principal intérêt de ce package est
de faciliter la mise au point des programmes.
SQL*Plus possède le paramètre SERVEROUTPUT qu’il faut activer à l’aide de la commande SET
SERVEROUTPUT ON pour connaître les informations qui ont été écrites dans le tampon.
1. ENABLE
Cette procédure permet d’activer les appels aux procédures PUT, PUT_LINE, NEW_LINE, GET_LINE et GET_LINES.
L’appel à cette procédure sera ignoré si le package DBMS_OUTPUT n’est pas activé.
Il n’est pas nécessaire de faire appel à cette procédure lorsque le paramètre SERVEROUTPUT est fixé depuis
SQL*Plus.
Syntaxe
Lorsqu’elle est spécifiée, la taille du tampon est au maximum de 1 000 000 d’octets et au minimum de 2 000 octets.
La valeur NULL permet d’avoir un tampon de taille illimitée.
Si plusieurs appels à cette procédure sont effectués, alors c’est la taille maximale du tampon qui est retenue.
2. DISABLE
Cette procédure permet de désactiver les appels aux procédures PUT, PUT_LINE, NEW_LINE, GET_LINE et GET_LINES
et vide le tampon de toutes les informations qu’il contient.
Il n’est pas nécessaire de faire appel à cette procédure lorsque le paramètre SERVEROUTPUT est fixé depuis
SQL*Plus.
Syntaxe
DBMS_OUTPUT.DISABLE
Cette procédure ne possède aucun paramètre.
3. PUT et PUT_LINE
Il est possible de placer directement une ligne d’informations dans le tampon à l’aide de PUT_LINE, ou bien de
construire petit à petit la ligne d’informations en plaçant les informations les unes à la suite des autres dans le
tampon par l’intermédiaire de la commande PUT. Ces deux procédures permettent de placer indifféremment dans le
tampon des données de type caractère (VARCHAR2), de type numérique (NUMBER) ou de type DATE.
Dans tous les cas, les données sont converties au format chaîne de caractères. Les données de type numérique ou
date sont formatées en utilisant la fonction de conversion TO_CHAR et en utilisant les formats de conversion par
défaut. Si l’on souhaite obtenir d’autres formats de conversion, alors il faut convertir les données en chaîne de
Si le volume des données à placer dans le tampon est supérieur à la taille du tampon alors une erreur est
levée.
Syntaxe
DBMS_OUTPUT.PUT(element IN NUMBER) ;
DBMS_OUTPUT.PUT(element IN VARCHAR2) ;
DBMS_OUTPUT.PUT(element IN DATE) ;
DBMS_OUTPUT.PUT_LINE(element IN NUMBER) ;
DBMS_OUTPUT.PUT_LINE(element IN VARCHAR2) ;
DBMS_OUTPUT.PUT_LINE(element IN DATE) ;
4. NEW_LINE
Cette procédure permet de placer un marqueur de fin de ligne dans le tampon.
Syntaxe
DBMS_OUTPUT.NEW_LINE ;
5. GET_LINE et GET_LINES
Il est possible de lire depuis le tampon une ligne simple d’informations en utilisant la procédure GET_LINE, ou bien de
ramener un tableau de lignes par l’intermédiaire de la procédure GET_LINES.
Après la lecture du tampon par les procédures GET_LINE ou GET_LINES, toutes les lignes non lues encore
présentes dans le tampon lors de l’appel suivant à PUT, PUT_LINE ou NEW_LINE sont supprimées afin
d’éviter toute confusion possible d’informations.
Syntaxe
Les paramètres sont les suivants :
ligne
Contient une seule ligne d’informations en provenance du tampon. Le marqueur de fin de ligne n’est pas contenu
dans la ligne retournée. La longueur maximale de cette ligne est de 32767 caractères.
état
Si l’appel a été un succès, alors l’état contient la valeur 0 et il contient 1 lorsque le tampon ne contient plus aucune
ligne d’informations.
lignes
C’est un tableau de VARCHAR2(32767).
nb_lignes
Le package DBMS_OUTPUT est, en règle générale, utilisé pour la mise au point des fonctions et des procédures
stockées, car l’affichage des informations placées dans le tampon est automatique depuis SQL*Plus.
Exemple
Procédure utilisant le package DBMS_OUTPUT :
Puis il faut exécuter cette fonction depuis SQL*Plus :
Syntaxe
UTL_FILE_DIR=c:\temp.
Pour rendre tous les répertoires accessibles par UTL_FILE côté serveur, il faut préciser le paramètre suivant
dans le fichier INIT.ORA : UTL_FILE_DIR=*
À partir la version 9i il est préférable d’utiliser la commande CREATE DIRECTORY pour gérer les répertoires accessibles
depuis le package UTL_FILE à la place du paramètre d’initialisation UTL_FILE_DIR.
Il est possible de connaître la liste des répertoires définis sur le serveur à l’aide de la vue ALL_DIRECTORIES.
Syntaxe
Un exemple d’utilisation de cette instruction est donné dans l’exemple récapitulatif du package.
1. FOPEN, FOPEN_NCHAR
Cette fonction permet d’ouvrir un fichier en vue d’effectuer des opérations de lecture ou d’écriture. Le chemin d’accès
au fichier doit correspondre à un répertoire valide défini à l’aide de CREATE DIRECTORY.
Le chemin complet d’accès doit exister, et FOPEN ne peut pas créer de répertoires.
La fonction FOPEN retourne un pointeur sur le fichier. Ce pointeur devra être précisé pour l’ensemble des opérations
de lecture/écriture qui seront effectuées par la suite.
Il n’est pas possible d’ouvrir plus de 50 fichiers de façon simultanée.
Syntaxe
UTL_FILE.FOPEN(
chemin IN VARCHAR2,
nom_fichier IN VARCHAR2,
mode_ouverture IN VARCHAR2,
taille_max_ligne IN BINARY_INTEGER DEFAULT 1024)
RETURN UTL_FILE.FILE_TYPE ;
chemin
Nom de l’objet DIRECTORY qui correspond au répertoire du système d’exploitation qui contient le fichier à ouvrir.
nom_fichier
Nom du fichier avec son extension, sans aucune information concernant le chemin d’accès.
Chaîne de caractères précisant le mode d’ouverture du fichier. Les valeurs possibles peuvent être :
r ouverture du fichier en lecture seule.
w ouverture du fichier en mode écriture.
a ouverture d’un fichier existant en mode ajout.
Lors de l’ouverture en mode a (ajout) d’un fichier qui n’existe pas, alors il est créé et ouvert en mode w
(écriture).
taille_max_ligne
Longueur maximum d’une ligne (caractère de fin de ligne compris). Doit être compris entre 1 et 32767 ; 1024 par
défaut.
La fonction FOPEN peut lever les exceptions suivantes : INVALID_PATH, INVALID_MODE ou INVALID_OPERATION.
La fonction FOPEN_NCHAR qui accepte les mêmes paramètres que la fonction FOPEN permet d’ouvrir un fichier en
mode UNICODE pour les lectures et les écritures. Avec cette méthode il est alors possible de lire et d’écrire un fichier
en UNICODE au lieu d’utiliser le jeu de caractères de la base de données.
2. IS_OPEN
La fonction IS_OPEN a pour but de tester si un pointeur de fichier correspond à un flux vers un fichier qui a bien été
ouvert et non encore fermé. La fonction IS_OPEN permet de tester la validité au niveau du package UTL_FILE et ne
permet en aucun cas d’être sûr que l’opération se déroulera sans problème de la part du système d’exploitation.
Si le pointeur de fichier passé en paramètre correspond à un flux ouvert, alors la fonction IS_OPEN retourne la valeur
TRUE, sinon elle retourne FALSE.
Syntaxe
UTL_FILE.IS_OPEN(
ptr_fichier IN FILE_TYPE)
RETURN BOOLEAN ;
3. FCLOSE
Cette procédure permet de fermer proprement un flux vers un fichier, et de s’assurer que les données situées dans le
tampon d’écriture sont bien enregistrées dans le fichier avant de fermer le flux vers celuici. Si des données sont
encore présentes dans le tampon au moment de la fermeture du fichier, alors la fonction FCLOSE peut lever l’erreur
WRITE_ERROR.
Syntaxe
4. FCLOSE_ALL
Cette procédure permet de fermer tous les flux vers des fichiers qui ont été ouverts au cours de la session actuelle.
Cette procédure ne doit être exécutée qu’avec parcimonie, par exemple lorsque l’on sort du bloc PL/SQL suite à une
levée d’exception.
De plus, la fonction FCLOSE_ALL n’affecte pas l’état des autres pointeurs de fichiers détenus par le même utilisateur.
C’estàdire que la fonction IS_OPEN, continuera à retourner vrai (TRUE) lors du test du flux, mais que toute tentative
d’utilisation de ce flux, soit en lecture, soit en écriture, est vouée à l’échec.
Syntaxe
ULT_FILE.FCLOSE_ALL ;
Cette procédure permet de lire une ligne entière de texte depuis le fichier identifié par le pointeur qui lui est passé en
paramètre, et retourne cette ligne d’informations dans une variable tampon qui lui est également passée en
paramètre. On trouve dans cette variable tampon, l’intégralité du texte sans le marqueur de fin de ligne ou de fin de
fichier (pour la lecture de la dernière ligne).
Cette procédure n’est autorisée que si le fichier a été ouvert en mode lecture (r). Dans tous les autres cas,
l’exception INVALID_OPERATION est levée.
Si la ligne est trop grande pour être contenue intégralement dans la variable tampon, alors une exception
VALUE_ERROR est levée. Au contraire, si l’on tente de lire le texte situé après la marque de fin de fichier, alors une
exception de type NO_DATA_FOUND est levée.
Comme le marqueur de fin de ligne n’est pas contenu dans la variable tampon, lors de la lecture, une ligne
blanche se traduit par une chaîne vide.
Syntaxe
UTL_FILE.GET_LINE(
ptr_fichier IN FILE_TYPE,
tampon OUT VARCHAR2,
octets_a_lire IN PLS_INTEGER DEFAULT NULL);
L’opération GET_LINE_NCHAR permet de lire du texte au format UNICODE depuis un fichier ouvert à l’aide de
FOPEN_NCHAR.
Syntaxe
UTL_FILE.GET_LINE_NCHAR(
ptr_fichier IN FILE_TYPE,
tampon OUT NVARCHAR2,
octets_a_lire IN PLS_INTEGER DEFAULT NULL);
L’opération GET_RAW va, quant à elle, permettre de lire des données de type RAW depuis un fichier.
Syntaxe
UTL_FILE.GET_LINE_RAW(
ptr_fichier IN FILE_TYPE,
tampon OUT NOCOPY RAW,
octets_a_lire IN PLS_INTEGER DEFAULT NULL);
6. PUT, PUT_NCHAR, PUT_RAW
La procédure PUT permet d’écrire le texte contenu dans une variable tampon vers le fichier. Le fichier doit bien
entendu avoir été ouvert en mode écriture (w ou a). Aucun marqueur de fin de ligne n’est ajouté de façon
automatique. Il faudra faire appel à la procédure NEW_LINE pour ajouter ce caractère de fin de ligne ou bien à la
procédure PUT_LINE pour compléter la ligne en cours et la terminer.
Syntaxe
UTL_FILE.PUT (
ptr_fichier IN FILE_TYPE,
tampon IN VARCHAR2) ;
La procédure PUT_RAW donne la possibilité d’inscrire des données de type RAW dans un fichier. Il est possible de
réclamer un vidage automatique du tampon à l’aide du troisième paramètre.
Syntaxe
7. NEW_LINE
Cette procédure permet d’ajouter un ou plusieurs caractères de fin de ligne au fichier. Cette procédure est à utiliser
pour terminer une ligne écrite à l’aide de la procédure PUT. Le nombre de caractères de fin de ligne ajoutés par
défaut est un.
Syntaxe
UTL_FILE.NEW_LINE(
ptr_fichier IN FILE_TYPE,
nombre IN NATURAL :=1) ;
8. PUT_LINE
Contrairement à la procédure PUT, cette procédure permet d’ajouter une ligne d’informations et son marqueur de fin
au fichier. Cette procédure peut être utilisée pour écrire une ligne dans sa totalité ou pour continuer et terminer une
ligne dont l’écriture a commencé avec la procédure PUT.
Syntaxe
UTL_FILE.PUT_LINE(
ptr_fichier IN FILE_TYPE,
tampon IN VARCHAR2),
vidage_auto IN BOOLEAN DEFAULT FALSE) ;
vidage_auto
Indique si le tampon doit être écrit sur disque immédiatement.
9. PUTF, PUTF_NCHAR
Cette procédure correspond à la procédure PUT, mais il est possible de formater les données. Son fonctionnement est
similaire à celui de la fonction printf du langage C. Il est possible d’écrire dans le fichier n’importe quel texte, mais les
caractères suivants possèdent un sens particulier :
%s
Ce caractère est remplacé par le paramètre de type caractère qui lui correspond.
\n
Ce caractère permet de marquer la fin d’une ligne.
Syntaxe
UTL_FILE.PUTF(
ptr_fichier IN FILE_TYPE,
tampon_formaté IN VARCHAR2[,
param1 IN VARCHAR2 DEFAULT NULL,
...
param5 IN VARCHAR2 DEFAULT NULL]);
Les paramètres sont optionnels. Ils sont au maximum au nombre de cinq. Le premier paramètre vient se substituer à
la première occurrence du caractère %s trouvée dans la chaîne tampon, le deuxième à la deuxième occurrence et
ainsi de suite.
Exemple
L’exemple suivant effectue le même travail mais il utilise un objet de type DIRECTORY pour accéder au système de fichiers.
DECLARE
-- TYPE ptr_fichier IS RECORD (id BINARY_INTEGER);
f_out UTL_FILE.FILE_TYPE;
BEGIN
-- ouvrir le fichier
f_out:=UTL_FILE.FOPEN(’FILE_DIR’,’test.txt’,’w’);
-- ecrire une ligne
UTL_FILE.PUT(f_out,’Ceci est un exemple’);
-- positionner une fin de ligne
UTL_FILE.NEW_LINE(f_out);
Le nom de l’objet DIRECTORY doit être mis en majuscules dans l’appel à FOPEN.
La procédure PUTF_NCHAR permet, quant à elle, l’écriture de chaînes de caractères UNICODE dans le fichier de
destination.
10. FFLUSH
Cette procédure permet d’écrire physiquement les données dans les fichiers, notamment celles qui se trouvent dans
le tampon d’écriture. En effet, normalement toutes les écritures vers les fichiers sont buffeurisées afin d’optimiser les
performances du disque. La procédure FFLUSH, permet de vider ce buffeur. Naturellement les données doivent se
terminer par un caractère de fin de ligne.
11. FSEEK, FGETPOS
La procédure FSEEK permet de se déplacer dans le fichier, en avant ou en arrière, du nombre d’octets désiré. Le
déplacement peut être absolu, le paramètre offset_absolu prend alors l’adresse sur laquelle il faut se positionner, la
valeur par défaut est null.
Dans le cas d’un déplacement relatif, c’est le troisième paramètre (offset_relatif) qui contient le nombre d’octets dont
UTL_FILE.FSEEK(
ptr_fichier IN FILE_TYPE,
offset_absolu IN PLS_INTEGER DEFAULT NULL,
offset_relatif IN PLS_INTEGER DEFAULT NULL);
La fonction FGETPOS permet de connaître l’offset de la position courante dans le fichier.
Syntaxe
UTL_FILE.FGETPOS(ptr_fichier IN FILE_TYPE)
RETURN PLS_INTEGER;
12. FREMOVE, FCOPY, FRENAME
Ces procédures permettent de réaliser un certain nombre d’opérations sur les fichiers du système d’exploitation
lorsque l’accès au répertoire a été accordé.
Ces procédures apportent une certaine souplesse dans la gestion des fichiers extérieurs à la base de données et
complètent la notion de DIRECTORY (répertoire) qui est introduite à partir de la version 9i.
L’emplacement est le nom d’un objet de type DIRECTORY qui a été créé à l’aide de la méthode CREATE DIRECTORY.
Syntaxe
UTL_FILE.FREMOVE(
emplacement IN VARCHAR2,
nom_fichier IN VARCHAR2);
UTL_FILE.FCOPY(
repertoire_origine IN VARCHAR2,
nom_fichier_origine IN VARCHAR2,
repertoire_destination IN VARCHAR2,
nom_fichier_destination IN VARCHAR2,
numero_ligne_debut IN PLS_INTEGER DEFAULT 1,
numero_ligne_fin IN PLS_INTEGER DEFAULT NULL);
UTL_FILE_FRENAME(
repertoire_origine IN VARCHAR2,
nom_fichier_origine IN VARCHAR2,
repertoire_destination IN VARCHAR2,
nom_fichier_destination IN VARCHAR2,
ecraser IN BOOLEAN DEFAULT FALSE);
13. FGETATTR
Cette procédure permet de lire et de retourner les attributs courants d’un fichier.
Syntaxe
UTL_FILE.FGETATTR(
emplacement IN VARCHAR2,
nom_fichier IN VARCHAR2,
existe OUT BOOLEAN,
taille_fichier OUT NUMBER,
taille_block OUT NUMBER);
14. Les exceptions
Les principales exceptions qui peuvent être levées lors de l’exécution de ce package sont :
INVALID_PATH
INVALID_MODE
Le mode d’ouverture du fichier précisé dans FOPEN est incorrect.
INVALID_FILEHANDLE
Le pointeur vers le fichier est invalide.
INVALID_OPERATION
Il est impossible de travailler avec le fichier.
READ_ERROR
Une erreur du système d’exploitation est survenue durant la lecture du fichier.
WRITE_ERROR
Une erreur du système d’exploitation est survenue durant une opération d’écriture sur le fichier.
INTERNAL_ERROR
Erreur PL/SQL non spécifiée.
CHARSETMISMATCH
Un fichier a été ouvert au moyen de la méthode FOPEN_NCHAR mais les opérations suivantes utilisent les fonctions
PUTF ou GET_LINE et non leur équivalent NCHAR.
FILE_OPEN
Echec de l’opération car le fichier est ouvert.
INVALID_MAXLINESIZE
INVALID_FILENAME
Le nom du fichier n’est pas correct.
ACCESS_DENIED
Permission d’accès au fichier refusée.
INVALID_OFFSET
Position incorrecte. La position passée en paramètre de la méthode FSEEK doit être plus grande que 0 et inférieure
au nombre total d’octets dans le fichier.
DELETE_FAILED
Échec de suppression du fichier.
RENAME_FAILED
Échec lors de la tentative de changement de nom du fichier.
Les procédures du package peuvent également lever des exceptions Oracle prédéfinies comme
NO_DATA_FOUND ou VALUE_ERROR.
Le travail avec les éléments de grande dimension (BLOB : Binary LOB, CLOB : Character LOB, NCLOB : uNicode CLOB et
BFILE: fichier binaire) n’est pas aussi facile qu’avec les données de type plus classique (caractère, nombre, date). Le
langage PL/SQL permet de travailler avec ces données à partir du moment où elles sont présentes dans la base mais
les opérations de chargement depuis un fichier du système d’exploitation de comparaison ou de modification ne peuvent
être réalisées qu’à l’aide du package DBMS_LOB.
1. Les constantes
Les constantes suivantes sont définies dans le package DBMS_LOB. Leur utilisation permet de clarifier l’utilisation des
différentes fonctions et procédures du package.
2. APPEND
Cette procédure permet d’ajouter la totalité de la variable LOB d’origine à la variable LOB de destination.
Syntaxe
DBMS_LOB.APPEND(
destination IN OUT NOCOPY BLOB,
source IN BLOB);
DBMS_LOB.APPEND(
destination IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
source IN CLOB CHARACTER SET destination%CHARSET);
3. CLOSE
Cette procédure permet de fermer un élément LOB interne ou externe qui a été ouvert précédemment.
Syntaxe
DBMS_LOB.CLOSE(
{lob_origine IN OUT NOCOPY BLOB
| lob_origine IN OUT NOCOPY CLOB CHARACTER SET ANY CS
| fichier_origine IN OUT NOCOPY BFILE);
4. COMPARE
Cette fonction permet de comparer deux LOB dans leur totalité ou partiellement. Il est uniquement possible de
comparer des LOB de même type (BLOB, CLOB ou BFILE). Pour les fichiers (BFILE) les éléments doivent être ouverts
avec FILEOPEN, avant leur comparaison.
La fonction COMPARE retourne 0 si les deux éléments à comparer sont parfaitement identiques et une valeur
différente de zéro dans le cas contraire.
Syntaxe
DBMS_LOB.COMPARE(
lob1 IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE},
lob2 IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE},
nombre_octets_a_comparer NUMBER :=DBMS_LOB.LOBMAXSIZE,
octet_origine1 IN INTEGER:=1,
5. COPY
Cette procédure permet de réaliser la copie totale ou partielle depuis un LOB d’origine vers un LOB de destination.
Dans le cas d’une copie partielle il est possible de préciser la longueur (en nombre d’octets) à copier ainsi que les
adresses dans le LOB d’origine et de destination.
Syntaxe
DBMS_LOB.COPY(
lob_destination IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
lob_origine IN{BLOB|CLOB CHARACTER SET lob_destination%CHARSET},
octets_a_copier IN INTEGER,
adr_destination IN INTEGER:=1,
adr_origine IN INTEGER:=1);
6. CREATETEMPORARY, FREETEMPORARY, ISTEMPORARY
La procédure CREATETEMPORARY permet de créer un CLOB ou un BLOB temporaire. L’espace nécessaire est pris sur le
tablespace temporaire.
Le paramètre cache permet de dire si le LOB doit être lu ou non depuis le tampon mémoire.
Le troisième paramètre permet d’indiquer si l’élément est temporaire à la session (par défaut) ou bien à l’appel.
Syntaxe
DBMS_LOB.CREATETEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
cache IN BOOLEAN,
validite IN PLUSIEURS_INTEGER:=DBMS_LOB.SESSION);
La procédure FREETEMPORARY permet de libérer un objet temporaire de type CLOB ou BLOB créé à l’aide de
CREATETEMPORARY. Il est bien sûr recommandé de ne pas attendre la fin de la session ou de l’appel pour que l’objet
temporaire soit supprimé mais de libérer l’espace qu’il occupe sur le tablespace temporaire le plus rapidement possible
à l’aide de la procédure FREETEMPORARY.
Syntaxe
DBMS_LOB.FREETEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS});
Enfin la fonction ISTEMPORARY qui retourne un booléen permet de savoir si l’élément LOB passé en paramètre est
temporaire ou non.
Syntaxe
DBMS_LOB.ISTEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS})
return INTEGER;
Exemple
L’exemple cidessous montre la mise en place de ces trois méthodes concernant les éléments LOB temporaires.
SQL> declare
2 b blob;
3 c clob;
4 begin
5 -- creation des éléments temporaires
6 dbms_lob.createtemporary(b, true);
7 dbms_lob.createtemporary(c,true);
8 -- test et suppression
9 if (dbms_lob.istemporary(b)=1) then
10 dbms_lob.freetemporary(b);
11 end if;
12
7. ERASE
Cette procédure a pour but d’effacer totalement ou partiellement un objet LOB. Dans le cas d’une suppression
partielle il est nécessaire de préciser le nombre d’octets à supprimer ainsi que l’adresse de départ.
Syntaxe
DBMS_LOB.ERASE(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANAY_CS},
octets_a effacer IN OUT NOCOPY INTEGER,
adr_depart IN INTEGER:=1);
8. FILEOPEN, FILECLOSE, FILECLOSEALL et ISOPEN
La procédure FILEOPEN permet d’ouvrir un fichier afin d’y effectuer des lectures. Il n’est pas possible d’écrire dans un
fichier ouvert à l’aide de cette procédure.
Syntaxe
DBMS_LOB.FILEOPEN(
ptr_fichier IN OUT NOCOPY BFILE,
mode_ouverture IN BINARY_INTEGER:=file_readonly);
Les procédures FILECLOSE et FILECLOSEALL permettent de fermer un fichier particulier ou tous les fichiers qui ont été
utilisés dans le cadre du travail avec les éléments de grande dimension à l’aide du package DBMS_LOB.
Syntaxe
Enfin, la fonction ISOPEN qui retourne un entier, permet de savoir si un élément LOB est ouvert ou non.
Syntaxe
DBMS_LOB.ISOPEN(
element_lob IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE})
RETURN INTEGER;
9. FILEEXIST, FILEISOPEN
Cette fonction retourne un entier indiquant si le fichier existe ou non. Il est intéressant de faire appel à cette fonction
avant de commencer à travailler avec le fichier, car on peut ainsi éviter de lever un certain nombre d’exceptions. Cette
fonction vérifie simplement l’existence physique du fichier.
La fonction retourne 0 si le fichier n’existe pas physiquement et 1 dans le cas contraire.
Syntaxe
Syntaxe
10. FILEGETNAME
Cette procédure permet de connaître l’emplacement et le nom du fichier correspondant à un objet de type BFILE.
Cette procédure n’indique en aucun cas si le répertoire et le fichier existent physiquement.
Syntaxe
DBMS_LOB.FILEGETNAME(
fichier IN BFILE,
repertoire OUT VARCHAR2,
nomfichier OUT VARCHAR2);
11. GETLENGTH, GETCHUNKSIZE
La fonction GETLENGTH permet de connaître la taille de l’élément LOB, BLOB ou BFILE passé en paramètre. La taille est
un nombre entier qui correspond au nombre d’octets de l’élément passé en paramètre.
Syntaxe
DBMS_LOB.GETLENGTH(
{lob_loc IN BLOB
| lob_loc IN CLOB CHARACTER SET ANY_CS
| file_loc IN BFILE}) RETURN INTEGER;
La fonction GETCHUNKSIZE permet quant à elle de connaître la taille réellement utilisée pour le stockage des
informations de l’élément LOB à l’intérieur des morceaux (CHUNK) d’espace physique accordés au LOB. Cette taille est
exprimée en octets.
Syntaxe
DBMS_LOB.GETCHUNKSIZE(
{lob_loc IN BLOB
| lob_loc IN CLOB CHARACTER SET ANY_CS
| file_loc IN BFILE}) RETURN INTEGER;
12. INSTR
Cette fonction retourne un entier correspondant à la n ième occurrence de l’élément cible recherché. Le numéro de
l’occurrence est indiqué par le paramètre nième, et la cible est contenue dans le paramètre cible. La recherche
commence dans l’élément LOB à partir d’une adresse de départ absolue contenue dans le paramètre adr_depart et
qui correspond à un nombre d’octets ou de caractères suivant la nature de l’élément LOB.
Syntaxe
DBMS_LOB.INSTR(
element_lob IN BLOB,
cible IN RAW,
adr_depart IN INTEGER:=1,
nieme IN INTEGER:=1);
DBMS_LOB.INSTR(
element_lob IN CLOB CHARACTER SET ANY_CS,
cible IN VARCHAR2 CHARACTER SET element_lob%CHARSET,
adr_depart IN INTEGER:=1,
nieme IN INTEGER:=1);
DBMS_LOB.INSTR(
element_lob IN BFILE,
13. LOADFROMFILE, LOADBLOBFROMFILE, LOADCLOBFROMFILE
Ces procédures permettent de charger des éléments LOB actuellement contenus dans des fichiers, à l’intérieur
d’éléments LOB de la base de données. Il est bien sûr possible de préciser les adresses absolues du début de la copie
dans le cadre d’un chargement partiel par l’intermédiaire des paramètres depart_origine et depart_destination. Ces
adresses sont exprimées en octets.
Dans tous les cas, il est nécessaire d’indiquer le nombre d’octets à lire depuis le fichier pour construire l’élément LOB
en mémoire.
Syntaxe
DBMS_LOADFROMFILE(
lob_destiniation IN OUT NOCOPY BLOB,
fichier_origine IN BFILE,
nombre_octets IN INTEGER,
depart_destination IN INTEGER:=1,
depart_origine IN INTEGER:=1);
DBMS_LOADBLOBFROMFILE(
lob_destiniation IN OUT NOCOPY BLOB,
fichier_origine IN BFILE,
nombre_octets IN INTEGER,
depart_destination IN OUT INTEGER:=1,
depart_origine IN OUT INTEGER:=1);
DBMS_LOADCLOBFROMFILE(
lob_destiniation IN OUT NOCOPY BLOB,
fichier_origine IN BFILE,
nombre_octets IN INTEGER,
depart_destination IN OUT INTEGER:=1,
depart_origine IN OUT INTEGER:=1,
jeu_caractere_org IN NUMBER,
contexte_langue IN OUT INTEGER,
avertissement OUT INTEGER);
Exemple
L’exemple cidessous illustre comment il est possible d’utiliser les différentes méthodes du package pour charger des images
dans une table.
Table créée.
Séquence créée.
SQL>
SQL> -- mise en place du répertoire
SQL> create or replace directory img_dir as ’C:\img’;
Répertoire créé.
SQL>
SQL> -- chargement des données
SQL> declare
2 fic_in BFILE;
3 taille number;
4 dest_blob BLOB;
5 vid number;
SQL>
14. OPEN
Cette procédure permet d’ouvrir un élément LOB dans le mode indiqué (lob_readonly ou lob_readwrite) à l’aide du
second paramètre.
Syntaxe
DBMS_LOB.OPEN(
lob_origine IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
mode_ouverture IN BINARY_INTEGER);
Cette procédure permet de lire en totalité ou en partie un élément LOB et de placer le résultat de cette lecture en
mémoire tampon.
Syntaxe
DBMS_LOB.READ(
lob_origine IN {BLOB|BFILE},
nombre_octets IN OUT NOCPY BINARY_INTEGER,
adr_depart INT INTEGER,
tampon OUT RAW);
DBMS_LOB.READ(
lob_origine IN CLOB CHARACTER SET ANY_CS,
nombre_octets IN OUT NOCPY BINARY_INTEGER,
adr_depart INT INTEGER,
tampon OUT VARCHAR2 CHARACTER SET lob_
origine%CHARSET);
16. SUBSTR
Cette fonction offre la possibilité d’extraire une souschaîne depuis l’élément LOB. C’est en fait l’ensemble des octets
lus à partir de l’adresse de départ passé en paramètre ainsi que le nombre d’octets à lire qui est retourné.
Syntaxe
DBMS_LOB.SUBSTR(
lob_origine IN BLOB,
nombre_octets IN INTEGER:=32767,
adr_depart IN INTEGER:=1) RETURN RAW;
DBMS_LOB.SUBSTR(
lob_origine IN CLOB CHARACTER SET ANY_CS,
nombre_octets IN INTEGER:=32767,
adr_depart IN INTEGER:=1)
RETURN VARCHAR2 CHARACTER SET lob_origine%CHARSET;
17. TRIM
Cette procédure permet de réduire la taille d’un élément LOB au nombre d’octets ou de caractères précisé dans le
paramètre nouvelle_taille.
Syntaxe
DBMS_LOB.TRIM(
lob_origine IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
nouvelle_taille IN INTEGER);
18. WRITE, WRITEAPPEND
La procédure WRITE permet de d’écrire un nombre d’octets dans un élément LOB interne, à partir d’une adresse de
départ. La procédure WRITE remplace toutes les informations qui existent déjà dans l’élément LOB cible à partir de
l’adresse de départ.
Syntaxe
DBMS_LOB.WRITE(
lob_destination IN OUT NOCOPY BLOB,
nombre_octets IN BINARY_INTEGER,
adr_depart IN INTEGER,
tampon IN RAW);
DBMS_LOB.WRITE(
lob_destination IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
nombre_octets IN BINARY_INTEGER,
La procédure WRITEAPPEND permet d’écrire les données de type LOB actuellement dans le tampon à la fin de
l’élément LOB de destination.
Syntaxe
DBMS_LOB.WRITEAPPEND(
lob_destination IN OUT NOCOPY BLOB,
nombre_octets IN BINARY_INTEGER,
tampon IN RAW);
DBMS_LOB.WRITEAPPEND(
lob_destination IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
nombre_octets IN BINARY_INTEGER,
tampon IN VARCHAR2 CHARACTER SET
lob_origine%CHARSET);
19. Les exceptions
Les principales exceptions du package DBMS_LOB sont :
INVALID_ARGVAL
Les arguments des fonctions et des procédures attendent des valeurs non NULL, mais un argument a reçu la valeur
NULL ou bien une valeur en dehors du domaine de définition de l’argument.
ACCESS_ERROR
Tentative d’écriture sur un LOB qui dépasse la taille limite.
NOEXIST_DIRECTORY
L’élément de type DIRECTORY n’existe pas pour le fichier actuel.
NOPRIV_DIRECTORY
L’utilisateur ne possède pas les droits nécessaires sur le DIRECTORY (répertoire) ou sur les fichiers pour mener à bien
ses opérations.
INVALID_DIRECTORY
La référence au répertoire (DIRECTORY) n’est pas valide dans le cas d’un premier accès ou sa définition a été modifiée
par l’administrateur de bases de données depuis la dernière utilisation.
OPERATION_FAILED
Échec de l’opération.
UNOPENED_FILE
Le fichier n’est pas ouvert.
OPEN_TOOMANY
Le nombre de fichiers ouverts simultanément a atteint la limite supérieure. Il est donc nécessaire de fermer des
fichiers pour pouvoir continuer.
La machine virtuelle Java intégrée dans le moteur Oracle, est totalement compatible avec le JDK de Sun.
La version du JDK est fixée suivant la version Oracle utilisée.
Cette machine virtuelle s’exécute dans le même processus et partage le même espace mémoire que le moteur de la
base de données. Cette solution offre de très bons temps d’accès aux données. La machine virtuelle est un
environnement d’exécution Java qui supporte toutes les structures, les méthodes et la gestion des erreurs propres à
Java.
Choisir Java pour développer du code côté serveur, c’est obtenir une solution applicative écrite entièrement en Java et
donc limiter le nombre de langages différents à apprendre.
Le langage Java peut intervenir pour l’écriture de procédures, de fonctions et de déclencheurs (triggers) de base de
données.
Les avantages des procédures stockées sont nombreux. Les plus importants sont :
● la performance : car le code exécutable est géré par le serveur et il y est maintenu en mémoire.
● la facilité de mise en place et de déploiement : tous les utilisateurs accèdent au même code.
● la sécurité : il est possible, en utilisant la sécurité Oracle, d’obliger les utilisateurs à manipuler les données au
travers des procédures stockées et de ne leur accorder aucun droit sur les tables accédées par les procédures.
Le développement d’applications Java en lien avec la base Oracle n’entre pas dans le cadre de cet ouvrage.
La présentation suivante permet d’explorer les capacités d’Oracle à travailler avec des procédures stockées
Java. Ce chapitre ne peut pas être considéré comme un apprentissage de Java et suppose d’avoir déjà
quelques notions de langage Java.
Pour charger les classes Java dans la base de données, nous utiliserons l’utilitaire en ligne de commandes
loadjava.
1. Généralités
Pour chaque classe chargée dans la base de données par loadjava, un objet est créé et le nom de cet objet est issu
du nom complet de la classe Java. Dans cet objet sont conservés le code source, le code exécutable et les différentes
ressources nécessaires à la bonne exécution de la classe. Loadjava conserve également les différentes valeurs des
options dans une table.
Le programme Java peut être mis au point par un outil de développement externe à la base de données, puis le
fichier .class est chargé par loadjava. Mais on peut tout à fait charger le fichier source (.java) et le code est alors
compilé dans la base de données.
Le nom de l’objet créé reprend le nom complet de la classe Java, c’estàdire le nom du package et le nom de la
classe. Ces noms peuvent avoir une longueur maximum de 4000 caractères dans la base de données. Mais Oracle
autorise des identifiants d’une longueur maximum de 30 caractères pour les objets de la base de données. Il faut
donc mettre en place une résolution de nom afin de pouvoir manipuler ces objets depuis PL/SQL.
2. Les droits d’utilisation
Par défaut, les procédures stockées Java utilisent les privilèges accordés à l’utilisateur Oracle qui exécute la
procédure. Ce type de résolution de droits permet de personnaliser au mieux les privilèges accordés à chaque
utilisateur. De plus, le code peut être centralisé en un point précis de la base de données et être utilisé de différentes
façons.
Dans cet exemple les deux utilisateurs Pierre et Anne utilisent la même procédure stockée Java (Analyse) qui
intervient sur la table Ventes. Comme la procédure stockée s’exécute en utilisant les droits accordés à l’utilisateur qui
l’exécute, elle accède aux tables que l’utilisateur possède. Donc dans ce cas le même code est partagé pour analyser
deux tables totalement différentes.
3. L’utilitaire Loadjava
Syntaxe
andresolve
Avec cette option, chaque classe chargée est marquée comme valide, c’estàdire que toutes les classes auxquelles
elle fait référence sont censées être dans la base.
resolve
Avec cette option, la classe est chargée dans la base puis une résolution est effectuée pour savoir si toutes les
Les options resolve et andresolve sont mutuellement exclusives. Si aucune des deux options n’est précisée,
alors la résolution des classes est effectuée au moment de l’exécution.
resolver
Cette option permet d’indiquer un chemin (ensemble de schémas) à utiliser pour trouver les objets référencés dans la
classe nouvellement chargée. Cette option s’apparente à la variable CLASSPATH que l’on utilise dans une
programmation Java classique.
oracleresolver
Cherche les objets dans le schéma de l’utilisateur courant et dans le schéma public. Si les classes demandées n’y
sont pas, alors l’objet nouvellement chargé est marqué comme invalide.
debug
Permet de générer des informations de débogage. Cette option est similaire à javac g.
definer
Permet d’utiliser la méthode avec les droits de l’utilisateur qui a créé cette méthode et non pas ceux accordés à
l’utilisateur qui utilise la méthode.
encoding
Cette option permet de fixer la table de caractères utilisée par le JDK pour encoder les fichiers. Par défaut, la page de
caractères utilisée est latin1.
force
La classe va être chargée dans la base même si elle y existe déjà. Sans cette option, l’action de chargement est
rejetée. Cette option est particulièrement intéressante dans les opérations de mise à jour des classes.
grant
Permet d’accorder le droit d’exécution de la procédure dès son chargement. Cette action est similaire à celle de
l’ordre SQL GRANT.
oci8
Autorise loadjava à communiquer avec la base en utilisant le pilote OCI JDBC. C’est le mode de communication par
défaut.
thin
Loadjava utilise dans ce cas le pilote thin JDBC pour communiquer avec la base.
Les options oci8 et thin sont mutuellement exclusives.
schema
Les objets Java nouvellement créés sont affectés au schéma précisé par ce paramètre. Par défaut ils sont créés dans
le schéma de l’utilisateur courant.
synonym
Un synonyme public est créé pour rendre les classes facilement accessibles.
verbose
Exemple
Le code source
La classe est chargée dans la base de données.
Utilisation de loadjava pour charger la classe dans le schéma livre
4. L’utilitaire Dropjava
À l’inverse de l’utilitaire Loadjava, Dropjava permet de supprimer un objet Java depuis la base de données. Cet outil
permet de supprimer aussi bien des fichiers source (.java), des fichiers .class, ou bien de ressources .jar ou .zip.
Syntaxe
Les options disponibles pour cet outil ont la même signification que dans l’utilitaire Loadjava.
Exemple
Suppression de la classe depuis le schéma livre
Que le programme Java s’exécute sur le poste client ou sur le serveur de base de données comme c’est le cas ici, le
problème de l’accès aux données se pose toujours. Avec Java, Oracle offre deux solutions distinctes d’accès aux
données. Il est possible d’utiliser la solution classique JDBC qui est déjà bien connue et c’est son principal avantage.
Une alternative à cette solution est proposée par l’intermédiaire de SQLJ. Avec cette technique, les commandes SQL
sont saisies directement dans le programme Java. Puis le fichier est enregistré avec l’extension sqlj au lieu de java.
La compilation du fichier SQLJ peut avoir lieu sur le poste client sur lequel est développé le code Java ou bien sur le
serveur. Il est préférable de réaliser une compilation sur le poste de développement car cela permet une mise au
point plus facile si des erreurs de compilation sont présentes.
Les fichiers .class ou .jar peuvent alors être chargés sur le serveur par l’intermédiaire de la commande loadjava.
a. JDBC
La mise en place d’une solution JDBC va permettre d’utiliser des outils connus et indépendants de la base Oracle.
Cette méthode est particulièrement bien adaptée dans le développement d’outils clients en Java qui ne doivent pas
être liés de façon trop contraignante à la base de données Oracle. Pour l’écriture de procédures stockées, la
syntaxe JDBC peut s’avérer un peu lourde comparée au SQLJ.
Dans cet ouvrage, de nombreux exemples Java utilisent la technologie JDBC pour travailler avec les données issues
de la base de données.
b. SQLJ
SQLJ est une solution d’accès aux données, spécifique à Oracle, qui est bien adaptée dans le cadre des
développements Java étroitement liés à la base Oracle. En effet, grâce à SQLJ il est possible de faire référence à
des variables Java directement dans les instructions SQL, et pour les applications s’exécutant sur le serveur de
base de données, la gestion de la connexion est implicite, ce qui simplifie encore le code.
Pour que le précompilateur SQLJ transforme les instructions SQLJ en appels de méthodes, les instructions SQLJ
doivent obligatoirement commencer par #SQL et l’instruction SQL est entre accolades {}.
Exemple
Le code Java cidessous montre comment il est possible d’intégrer les commandes SQLJ dans le code Java.
import java.sql.*;
class Comptes{
public static int CompteClients(){
int nombre=0;
try{
#sql{SELECT COUNT(*) INTO :nombre FROM CLIENTS};
return nombre;
} catch(SQLException e){
}finally{
return nombre;
}
}
}
Il est ensuite nécessaire de compiler le fichier sqlj afin de générer le fichier class.
sqlj Comptes.sqlj
Enfin, le fichier class doit être chargé dans la base à l’aide de l’utilitaire loadjava.
1. Correspondance des types de données
La correspondance entre les types de données SQL et Java est régie par le tableau page suivante.
Type SQL Classe Java
CHAR NCHAR LONG VARCHAR2 NVARCHAR2 oracle.sql.CHAR
java.lang.String
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.BigDecimal
byte short int long float double
DATE oracle.sql.DATE
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.lang.String
NUMBER oracle.sql.NUMBER
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.BigDecimal
byte short int long float double
RAW LONG RAW oracle.sql.RAW
byte[]
java.lang.String
BFILE oracle.sql.BFILE
BLOB oracle.sql.BLOB
oracle.jdbc2.Blob
CLOB NCLOB oracle.sql.CLOB
oracle.jdbc2.Clob
OBJECT oracle.sql.STRUCT
oracle.jdbc2.Struct
REF oracle.sql.REF
oracle.jdbc2.Ref
TABLE VARRAY oracle.sql.ARRAY
oracle.jdbc2.ArrayArray
2. Création d’une fonction Java ou d’une procédure Java
Syntaxe
AUTHID
Permet de définir le type de privilèges à utiliser lors de l’exécution de la méthode, soit ceux de l’auteur de la méthode,
soit ceux de l’utilisateur de la méthode (par défaut).
Il n’est pas possible d’écraser un choix réalisé avec Loadjava.
PARALLEL_ENABLE
La méthode peut s’exécuter dans un environnement parallèle car elle ne fait référence à aucune valeur de type static.
DETERMINISTIC
Lorsque le résultat de la fonction ne dépend pas de variables de session, alors l’optimiseur peut réutiliser le résultat
déjà obtenu lors d’un appel précédent avec les mêmes paramètres.
Exemples
Définition de la procédure associée à la méthode Supprime :
L’exemple ciaprès définit une fonction qui retourne le nombre d’éléments dans la table dont le nom est passé en
paramètre.
Le code java
Par l’intermédiaire de l’utilitaire Loadjava, la classe est chargée dans la base.
Puis une fonction de type PL/SQL est créée afin de pouvoir utiliser la fonction Java dans la base.
Définition de la fonction associée à la méthode Compte
3. CREATE JAVA
L’instruction DDL CREATE JAVA permet de créer une procédure, une fonction ou une ressource Java depuis l’invite SQL
sans passer par l’utilitaire loadjava. L’utilisation d’une telle commande est réservée au code java pour lequel le risque
d’erreurs de compilation est rare car la mise au point est plus difficile.
Comme toutes les commandes du DDL il est nécessaire d’avoir un privilège particulier (ici CREATE PROCEDURE) pour
pouvoir exécuter cette instruction.
Syntaxe
La syntaxe cidessus est un extrait de la syntaxe complète de la commande CREATE JAVA. C’est cette syntaxe qui
servira le plus souvent mais il possible de la compléter lors de l’utilisation de données de type BLOB, CLOB ou BFILE
ou lorsque la procédure doit être créée sur un schéma différent de l’utilisateur courant.
Exemple
L’exemple cidessous montre la mise en place d’une fonction Java à l’aide de la commande CREATE JAVA.
Dans l’exemple suivant c’est, cette fois, un fichier class qui est chargé dans la base à l’aide de la commande CREATE JAVA.
1. Appel d’une procédure Java depuis SQL*Plus
L’instruction CALL
L’instruction CALL permet d’appeler depuis le prompt PL/SQL une procédure stockée Java qui a été publiée en tant que
fonction, procédure ou élément d’un package.
Syntaxe
CALL [nom_schéma.][nom_package.]
{nom_procedure(paramètre,...)|nom_fonction(paramètre,...)}
Les paramètres sont définis dans SQL*Plus et peuvent être des littéraux ou bien des variables hôtes.
Exemple
Utilisation de la fonction Compte pour connaître le nombre de clients présents dans la table.
Création de la table TTEST puis suppression par la procédure Java Supprime_le.
Rediriger les sorties
Certaines procédures stockées Java utilisent le flux standard d’erreur (System.err) ou de sortie (System.out) pour
afficher certaines informations. Il est possible de rediriger ces flux vers SQL*Plus en utilisant simplement les deux
commandes suivantes :
Avec ce principe, les données sont affichées dès que la procédure est terminée. Le paramètre taille, dont la valeur par
défaut est 2000 octets permet de préciser la taille du tampon. Cette taille ne peut pas être supérieure à 1 000 000
d’octets.
La classe va être chargée dans la base par l’intermédiaire de Loadjava. Une procédure PL/SQL est associée à la méthode
Java.
La publication dans la base.
Utilisation de la procédure depuis SQL*Plus.
2. Appel d’une procédure Java depuis un déclencheur de base de données
Un déclencheur de base de données est un programme associé à une table ou une vue. Ce programme est exécuté
automatiquement par Oracle lorsque l’opération DML (INSERT, UPDATE ou DELETE) à laquelle le déclencheur est lié, est
exécutée sur la table ou sur la vue. Après la définition du trigger : nom, table ou vue associée, ordre DML déclencheur,
avant ou après vérification des contraintes d’intégrité, la procédure liée à la méthode Java est appelée à l’aide de la
fonction CALL. Le corps déclencheur est alors réduit au maximum.
Exemple
La classe Declencheurs propose une méthode qui permet de réduire le stock à chaque nouvelle commande d’articles. La
classe est chargée dans la base à l’aide de l’utilitaire Loadjava. Création de la procédure MAJStock.
Le déclencheur est posé sur la table LIGNESCDE et il est associé à l’ordre INSERT. Le déclencheur est exécuté pour chaque
ligne créee. Création du déclencheur.
3. Appel d’une procédure Java depuis une instruction SQL DML ou un bloc PL/SQL
Comme une fonction ou une procédure de type PL/SQL est associée à la méthode Java, l’utilisation de cette fonction
ou procédure est similaire à celle d’une fonction ou procédure écrite entièrement en PL/SQL.
Les packages
La mise en place de méthodes Java n’est pas toujours évidente et de plus il est aberrant de créer autant de classe
Java que de méthodes. Au niveau Java, toutes les méthodes traitant d’un même sujet, par exemple la gestion des
commandes, sont regroupées dans la même classe. Pour maintenir cette cohérence de regroupement au niveau de la
programmation dans la base de données, les fonctions et les procédures associées aux méthodes sont regroupées
dans un package.
Bien sûr, un tel package ne diffère pas d’un package PL/SQL et se comporte de la même façon. Le point le plus
important étant que le package reste entièrement en mémoire et permet ainsi d’offrir de meilleurs temps de réponse
Création de la classe Commandes.
import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;
}
}
La classe est chargée dans la base par l’intermédiaire de la commande Loadjava. Le package lui correspondant sera
créé en deux étapes. Tout d’abord l’entête du package est défini :
Puis le corps du package est défini.
L’utilisation d’une procédure ou d’une fonction de ce package est en tout point identique à celle d’un package écrit
entièrement en PL/SQL.
Exemple
Utilisation de la fonction Montant pour connaître le montant de la commande n°1.
Le langage PL/SQL, qui est couramment utilisé par les développeurs Oracle, voit ainsi ses possibilités évoluer vers le
XML. Le parser XML pour PL/SQL a été écrit en PL/SQL et en Java. Il supporte toutes les spécifications émises par le
W3C pour la norme 1.0 de XML. En plus du respect total de la norme, le parser XML pour PL/SQL permet une analyse
simplifiée du document par le respect des consignes du W3C concernant le modèle de document (DOM : Document
Object Model). Il respecte également les recommandations concernant XSLT (les feuilles de styles) et Xpath.
Le parser est situé dans le répertoire $ORACLE_HOME\xdk\plsql\parser. Il est inclus en standard à partir de la
version 9i.
Le schéma suivant résume simplement comment fonctionne le parser pour l’analyse d’un document. Cette arborescence est
ensuite mise en œuvre dans les exemples qui suivent afin de connaître la structure d’un document ainsi que les données
contenues dans ce document.
Ainsi, tous les programmes possèdent la même structure pour pouvoir analyser un document XML, qui est la suivante :
● Créer un nouvel objet de type Parser à l’aide de la fonction newParser et commencer l’analyse du document XML
ainsi que de sa DTD si elle est disponible.
● Ensuite, il faut utiliser la source XML ou DTD qui peut être de type varchar2, CLOB (Character Large Object Binary)
ou un fichier.
● Suivant le type de la source, les méthodes possibles sont parse() ou parseDTD() si les informations sont
contenues dans un fichier, parseBuffer() ou parseDTDBuffer() si les informations sont contenues dans un
élément de type varchar2 et enfin parseClob() ou bien parseDTDClob() si les informations sources sont
conservées dans un élément de type CLOB.
● Pour les documents XML uniquement qui sont analysés à l’aide d’une des fonctions parse, parseBuffer ou
parseClob, le résultat de l’exécution de ces méthodes est placé dans un document accessible par getDocument
().
● La méthode freeDocument va permettre de libérer les ressources actuellement détenues par le parser sur le
document actif afin de rendre possible l’analyse d’un autre document.
● Enfin, l’instruction freeParser() permet de libérer toutes les ressources.
Le script suivant va donc permettre la création d’une procédure qui accepte en paramètre un nom de fichier xml et qui va
l’ouvrir afin d’interpréter les données qu’il contient.
-- obtenir le document
doc:=xmlParser.GetDocument(p);
-- libérer le document
xmlDom.freeDocument(doc);
-- libérer le parser
xmlParser.freeParser(p);
end;
/
show errors;
C’est la procédure lireXml qui va permettre de lire et d’analyser un document XML. Le document XML va être fourni en
paramètre de la procédure :
L’exécution de la procédure et le résultat de cette exécution sont les suivants :
SQL>
espaceNom varchar2(50);
-- les éléments pour produire le résultat
documentF xmlDom.DOMDocumentFragment;
elementF xmlDom.DomNode;
begin
-- création d’un nouveau parser
p:=xmlParser.newParser;
-- obtenir le document
documentXml:=xmlParser.getDocument(p);
-- obtenir le document
documentXsl:=xmlParser.getDocument(p);
L’utilisation de cette procédure permet d’appliquer une feuille de style (XSL) à un document XML et le résultat est fourni
sous la forme d’un troisième document. Le fichier des erreurs est passé en paramètre et c’est à l’intérieur de celuici
que sont consignées toutes les erreurs trouvées lors de l’application de la feuille de style.
L’appel de la procédure peut s’effectuer de la façon suivante :
execute appliqueXsl(’c:\xml’,’equipe.xml’,’equipe.xsl’,’equipe.out’,
’erreurs.txt’);
1. Génération de code XML avec DBMS_XMLQuery
Pour pouvoir générer un document XML qui va contenir le résultat d’une requête simple à l’aide de DBMS_XMLQuery, il
est nécessaire de suivre les cinq étapes suivantes :
● Créer un pointeur vers un contexte en appelant la méthode DBMS_XMLQuery.getCtx et en lui passant en
paramètre la requête.
● Saisir les valeurs des différents paramètres possibles de la requête à l’aide de DBMS_XMLQuery.bind.
● Fixer les arguments optionnels comme le nom de la balise ROW ou ROWSET, le nombre de lignes à ramener...
● Écrire les données XML dans un élément CLOB (Caractère LOB) à l’aide de la fonction DBMS_XMLQuery.getXML.
Cette fonction peut travailler avec ou sans un fichier DTD ou un schéma.
● Fermer le contexte.
a. Génération de code XML depuis une requête
L’exemple cidessous illustre de façon très simple comment générer des informations au format XML à partir de ce qui est
contenu dans la base.
set serveroutput on
-- Mise au format XML du résultat d’une requête
declare
contexteRqt DBMS_XMLQuery.ctxType;
resultat CLOB;
begin
-- mise en place du contexte de requête
contexteRqt:=DBMS_XMLQuery.newContext(’select * from clients’);
-- obtenir le résultat
resultat:= DBMS_XMLQuery.getXML(contexteRqt);
-- afficher le résultat
afficheCLOB(resultat);
Afin de faciliter l’affichage des éléments au format CLOB, la méthode afficheCLOB a été écrite.
L’exécution de ce script donne alors le résultat suivant :
Le résultat est bien sûr satisfaisant sur de nombreux points mais n’est pas encore un document XML utilisable tel
quel.
b. Modifier les noms des balises ROW et ROWSET
L’API XSU pour PL/SQL permet de modifier le nom des balises ROW et ROWSET. Dans le cadre de notre exemple, la
balise ROW devrait prendre le nom de CLIENT et la balise ROWSET celle de CLIENTS. En modifiant légèrement le
script précédent et en utilisant les méthodes setRowTag et setRowSetTag il est possible d’effectuer ces
modifications.
Le script de génération de code XML devient alors :
set serveroutput on
-- Mise au format XML du résultat d’une requête
declare
contexteRqt DBMS_XMLQuery.ctxType;
resultat CLOB;
begin
-- mise en place du contexte de requête
contexteRqt:=DBMS_XMLQuery.newContext(’select * from clients’);
-- obtenir le résultat
resultat:= DBMS_XMLQuery.getXML(contexteRqt);
-- afficher le résultat
afficheCLOB(resultat);
Le résultat de l’exécution du script est alors :
c. Limiter le nombre de lignes
Les lignes de données extraites à partir de la requête peuvent être mises en page à l’aide des procédures
setMaxRowset setSkipRows. La procédure setMaxRows permet de fixer le nombre maximum de lignes de données qui
seront converties au format XML, la procédure setSkipRows permet quant à elle de préciser le nombre de lignes de
données à ne pas prendre en compte avant de commencer la conversion au format XML.
Ces procédures peuvent être utilisées pour, par exemple, limiter le nombre de lignes de données présentées dans
chaque document XML.
L’exemple suivant permet de limiter à 10 le nombre de clients présents dans chaque document XML généré. Afin qu’une
exception soit levée lorsque toutes les lignes sont traitées, il faut faire appel à la méthode setRaiseNoRowsException.
set serveroutput on
-- Mise au format XML du résultat d’une requête
declare
contexteRqt DBMS_XMLQuery.ctxType;
resultat CLOB;
begin
-- mise en place du contexte de requête
contexteRqt:=DBMS_XMLQuery.newContext(’select * from clients’);
-- afficher le résultat
afficheCLOB(resultat);
end loop;
exception
when others then
null; --sortir du bloc en cas d’erreur
end;
d. Les feuilles de styles
L’API XSU permet, bien sûr, l’utilisation des feuilles de styles dans la génération des documents XML.
La procédure setStyleSheetHeader() permet d’ajouter la référence à la feuille de style dans l’entête du document
résultant.
La procédure useStyleSheet() permet, quant à elle, d’appliquer la feuille de style directement au document
résultant. La seconde solution est de meilleure qualité que la première car cela évite de retravailler le document pour
appliquer la feuille de style dans un deuxième temps.
2. Les requêtes paramétrées
Lors de la création du contexte il est nécessaire de fournir la requête SQL qui sera utilisée pour extraire l’information.
Toutefois, cette requête peut contenir des paramètres qui seront valorisés juste avant l’exécution de la requête. En
effet la requête n’est exécutée que lors de la demande de construction du document XML final par l’intermédiaire de la
méthode getXMLClob.
Lors de l’écriture de la requête, les variables sont considérées comme des variables externes et sont donc préfixées
par deux points (:).
La méthode setBindValue permet de fixer la valeur qui sera utilisée par un paramètre. Il est bien sûr nécessaire
d’initialiser l’ensemble des paramètres avant la première demande de génération de document XML. Cependant, entre
deux demandes de génération de document, il n’est pas nécessaire de réinitialiser tous les paramètres mais
simplement ceux pour lesquels la valeur a changé.
Exemple
L’exemple suivant permet d’illustrer la mise en place de requêtes paramétrées pour travailler avec l’API XSU. Deux
documents XML vont être générés, chacun d’eux correspondant à la définition d’un client particulier, mais pourtant un seul
contexte XSU sera établi car les données sont issues de la même requête à un paramètre de restriction prêt.
set serveroutput on
-- Mise au format XML du résultat d’une requête
declare
contexteRqt DBMS_XMLQuery.ctxType;
resultat CLOB;
begin
-- mise en place du contexte de requête
contexteRqt:=DBMS_XMLQuery.newContext(’select * from clients where
nocli=:numero’);
-- obtenir le résultat
resultat:= DBMS_XMLQuery.getXML(contexteRqt);
-- afficher le résultat
afficheCLOB(resultat);
-- obtenir le résultat
resultat:= DBMS_XMLQuery.getXML(contexteRqt);
-- afficher le résultat
afficheCLOB(resultat);
-- fermer le contexte de requête
DBMS_XMLQuery.closeContext(contexteRqt);
end;
/
3. Stocker les informations au format XML avec DBMS_XMLSave
L’API XSU pour PL/SQL est également constituée du package DBMS_XMLSave qui permet d’enregistrer dans des tables
de la base de données Oracle des données qui se trouvent initialement dans des documents au format XML. Avec ce
second package, XSU permet de montrer que XML est un véritable format d’échange des données qui peut être utilisé
pour effectuer des transferts de données entre des bases de données.
Il sera possible de travailler avec les données fournies au format XML pour réaliser des commandes Insert, Update ou
Delete.
D’une façon générale, tous les scripts PL/SQL utilisant le package DBMS_XMLSave respectent la structure suivante :
● Créer un contexte d’exécution par l’intermédiaire de la fonction DBMS_XMLSave.getCtx. Cette fonction admet
en paramètre le nom de la table sur laquelle seront effectuées les opérations Insert, Delete ou Update.
● Si le document XML est utilisé comme support à l’ajout de données (INSERT) dans la table, alors il est possible
de préciser les colonnes pour lesquelles des valeurs vont être fournies par l’intermédiaire de la fonction
setUpadetColNames. Par défaut les valeurs sont fournies pour toutes les colonnes de la table.
● Si le document XML est un support à une opération de mise à jour des données (UPDATE), alors il faut fournir
la ou les colonnes qui vont être utilisées pour identifier de façon exacte les données à modifier. Il peut
également être possible de préciser la ou les colonnes qui seront mises à jour.
● Si le document XML sert de support à une opération de suppression (DELETE), alors il est possible de préciser
quelles seront la ou les colonnes qui seront utilisées pour identifier précisément les données à supprimer. Par
défaut toutes les informations du document XML servent à identifier les données qui seront supprimées.
● Fournir un document XML à l’une des méthodes insertXML, updateXML ou deleteXML suivant l’utilisation que
l’on souhaite faire du document XML.
● Fermer le contexte.
a. Ajouter des données
Pour utiliser les données présentes dans le document XML afin de les ajouter dans une table, il suffit simplement de
préciser le nom de la table ou de la vue, ainsi que le document XML. XSU se charge de générer les commandes
INSERT. Par défaut, la commande INSERT concerne toutes les colonnes de la table ou de la vue et la valeur NULL est
utilisée lorsque rien n’est précisé dans le document XML.
Exemple
L’exemple ciaprès illustre l’utilisation de la fonction insertXML :
Le document XML utilisé pour ajouter des données est :
L’appel à la procédure est effectué de la façon suivante :
dest_clob CLOB;
fic_in BFILE;
taille number;
depart_destination integer:=1;
depart_origine integer:=1;
jeu_caractere number:=0;
contexte_langue number:=0;
avertissement number:=0;
vid number;
begin
fic_in:= bfilename(’xml_dir’,’donnees.xml’);
-- ouvrir le fichier
dbms_lob.fileopen(fic_in, dbms_lob.file_readonly);
if (dbms_lob.fileexists(fic_in)=1) then
-- taille du fichier
taille:=dbms_lob.getlength(fic_in);
-- fermer le fichier
dbms_lob.fileclose(fic_in);
end if;
Il est également possible d’utiliser cette méthode d’insertion pour ne renseigner que certaines colonnes de la table
de destination. Il est alors nécessaire de faire appel à la méthode setUpdateColumn afin de préciser le nom des
colonnes qui vont contenir des valeurs à insérer. Pour éliminer tout risque de paramètre mal défini, la méthode
clearUpdateColumnList permet d’enlever toute référence qui aurait déjà pu être faite sur des colonnes.
Exemple
L’exemple suivant va lire les données au format XML dans un fichier puis charge les données dans la table des clients :
declare
-- la variables nécessaires à la lecture d’un fichier
documentXML CLOB;
fic_in BFILE;
taille number;
depart_destination integer:=1;
depart_origine integer:=1;
jeu_caractere number:=0;
contexte_langue number:=0;
avertissement number:=0;
begin
fic_in:= bfilename(’xml_dir’,’donnees2.xml’);
-- ouvrir le fichier
dbms_lob.fileopen(fic_in, dbms_lob.file_readonly);
-- taille du fichier
taille:=dbms_lob.getlength(fic_in);
-- fermer le fichier
dbms_lob.fileclose(fic_in);
end;
/
La mise à jour est une opération légèrement plus délicate car il est nécessaire cette fois d’indiquer la ou les colonnes
servant à l’identification de la ligne ainsi que la ou les colonnes dont les valeurs vont être mises à jour.
Les colonnes servant à l’identification seront indiquées par l’intermédiaire de la procédure setKeyColumn et celles qui
vont être mises à jour par l’intermédiaire de setUpdateColumn. En l’absence de cette dernière indication ce sont
toutes les colonnes de la table qui sont mises à jour.
Exemple
L’exemple cidessous va permettre de fixer la ville et le code postal pour les clients n°200 et 201 (ajoutés dans les
exemples précédents) :
declare
-- la variables nécessaires à la lecture d’un fichier
documentXML CLOB;
fic_in BFILE;
taille number;
depart_destination integer:=1;
depart_origine integer:=1;
jeu_caractere number:=0;
contexte_langue number:=0;
avertissement number:=0;
-- ouvrir le fichier
dbms_lob.fileopen(fic_in, dbms_lob.file_readonly);
-- taille du fichier
taille:=dbms_lob.getlength(fic_in);
end;
/
Le fichier XML servant de base à la mise à jour :
c. Supprimer des données
Enfin, il est possible de se servir d’un document XML comme support à la suppression de données. Les colonnes
présentes dans le document XML vont servir à la construction de la clause WHERE. Il est possible de restreindre le
nombre de colonnes participant à la restriction des lignes en faisant appel à la procédure setKeyColumn.
L’exemple suivant permet de supprimer les clients n° 200 et 201. Ces informations sont stockées dans un fichier XML
nommé donnees4.xml.
declare
-- les variables nécessaires à la lecture d’un fichier
documentXML CLOB;
fic_in BFILE;
taille number;
depart_destination integer:=1;
depart_origine integer:=1;
jeu_caractere number:=0;
contexte_langue number:=0;
avertissement number:=0;
begin
fic_in:= bfilename(’xml_dir’,’donnees4.xml’);
-- ouvrir le fichier
dbms_lob.fileopen(fic_in, dbms_lob.file_readonly);
-- taille du fichier
taille:=dbms_lob.getlength(fic_in);
end;
/
L’utilisation telle quelle du package DBMS_XMLSave est un peu fastidieuse dans l’écriture des procédures,
notamment au niveau de l’initialisation du contexte. Étant donné que le contexte est lié à une table, il est possible
de créer un contexte unique puis de l’utiliser, aussi bien pour effectuer des opérations d’ajout que de mise à jour ou
de suppression. Cette opération est réalisable en regroupant les procédures relatives aux différentes opérations
dans un package et en déclarant comme variable globale au package le contexte d’exécution des commandes du
package DBMS_XMLSave.
Avec APEX, il est possible de travailler avec un serveur Oracle sans pour autant maîtriser le langage SQL. Cependant,
des connaissances en SQL et PL/SQL vont permettre de travailler de façon précise. L’interface APEX est alors utilisée
pour éviter les erreurs de syntaxe et faciliter la saisie des opérations fastidieuses.
APEX permet de mettre en place, de façon très simple, une application de type Web qui utilise des données stockées
dans la base de données Oracle.
Pour activer APEX, il faut procéder de la manière suivante :
■ Sur le serveur Oracle, lancez SQL*Plus et connectezvous en tant que SYS.
C:\>sqlplus /nolog
■ Exécutez le script apxconf.sql situé dans le répertoire apex de l’installation Oracle et saisissez un mot de passe pour
l’administrateur APEX ainsi que le port à utiliser pour le serveur HTTP (8080 par défaut).
SQL> @?/apex/apxconf.sql
PORT
----------
8080
Enter values below for the XDB HTTP listener port and the password
for the Application Exp
ress ADMIN user.
Default values are in brackets [ ].
Press Enter to accept the default value.
Session modifiée.
Validation effectuée.
■ Déverrouillez le compte ANONYMOUS.
Utilisateur modifié.
Par ailleurs, par défaut, seule la langue anglaise est installée dans APEX.
Pour installer d’autres langues (par exemple, le français), vous pouvez procéder de la manière suivante :
■ Toujours sur le serveur Oracle, au niveau du système d’exploitation, définissez la variable d’environnement
NLS_LANG pour utiliser le jeu de caractères AL32UTF8.
■ Lancez SQL*Plus, connectezvous en tant que SYS et définissez le schéma APEX comme schéma courant.
C:\>sqlplus /nolog
Session altered.
■ Exécutez le script correspondant à la langue souhaitée.
SQL> @?/apex/builder/fr/load_fr.sql
...
Le chargement dure plusieurs minutes.
Vous pouvez vous connecter avec le nom d’utilisateur admin et le mot de passe indiqué lors la configuration.
Lors de la première connexion, vous serez invité à modifier le mot de passe et la page de connexion vous sera
proposée une deuxième fois.
La page d’accueil de l’interface d’administration a l’allure suivante :
■ Cliquez sur l’icône Gérer les espaces de travail :
Cette page permet de gérer les espaces de travail.
■ Pour créer un nouvel espace de travail, cliquez sur le lien Créer un espace de travail.
■ Sur la première page, saisissez un nom pour l’espace de travail puis cliquez sur le bouton Suivant >.
■ Sur la page suivante, vous allez indiquer si l’espace de travail est associé à un schéma existant, ou si un nouveau
schéma doit être créé. Dans cet exemple, nous allons créer un nouveau schéma. Pour cela, vous devez indiquer un
nom, un mot de passe et une taille. Cliquez ensuite sur le bouton Suivant >.
■ Pour terminer, vous devez créer un administrateur pour le nouvel espace de travail. Pour cela, saisissez un nom, un
mot de passe et une adresse de courrier électronique. Cliquez sur le bouton Suivant > pour afficher une page de
récapitulatif.
Si les informations sont correctes, vous pouvez cliquer sur le bouton Créer pour valider la création de l’espace de
travail. Lorsque la création est terminée, une page de confirmation s’affiche :
■ Cliquez sur le bouton Terminé.
À ce stade, il est possible de créer d’autres utilisateurs : développeurs d’applications qui vont pouvoir travailler dans un
espace de travail, ou utilisateurs finaux des applications développées avec APEX.
Dans cet ouvrage, le compte administrateur de l’espace de travail sera utilisé comme compte de développement.
1. Se connecter à l’espace de travail
Pour développer une application avec APEX, il faut se connecter à un espace de travail à l’aide d’un compte
développeur, avec une URL du type : http://serveur:port/apex, où serveur désigne le nom du serveur Oracle et port le
port d’écoute du serveur HTTP indiqué lors de la configuration (8080 par défaut).
■ Dans la page de connexion, saisissez le nom de l’espace de travail, ainsi que le nom et le mot de passe d’un
compte développeur habilité à travailler dans l’espace de travail. Comme indiqué précédemment, dans nos
exemples, nous utiliserons le compte administrateur de l’espace de travail comme compte développeur. Cliquez
ensuite sur le bouton Connexion pour accéder à la page d’accueil de l’espace de travail :
L’espace de travail est divisé en trois outils principaux :
● Application Builder permet de développer une application dont l’interface graphique se présente sous la
forme de pages HTML, contenant des formulaires pour saisir des données et des rapports. Les données
saisies dans l’application sont stockées dans des tables du schéma sousjacent.
● SQL Workshop propose plusieurs outils qui permettent de saisir et exécuter des requêtes SQL (ou des blocs
PL/SQL), mais aussi de gérer les différents objets du schéma (tables, vues, etc.).
● Utilitaires permet notamment d’exporter et d’importer très facilement des données.
2. Créer les objets de l’application
SQL Workshop propose un outil Navigateur d’objet qui permet de gérer les objets (tables, vues, séquences, etc.)
de l’application.
En guise d’exemple, nous allons utiliser cet outil pour créer les deux tables de notre application.
■ Ouvrez le menu déroulant associé au bouton SQL Workshop et sélectionnez l’élément Navigateur d’objet Créer
Table.
■ Sur la première page, saisissez le nom de la table et la liste des colonnes, puis cliquez sur le bouton Suivant >.
Sur la deuxième page, vous pouvez définir la clé primaire. Si vous le souhaitez, vous pouvez demander à ce que la clé
primaire soit renseignée automatiquement à partir d’une séquence (existante ou nouvelle). Sur l’exemple cidessus,
la clé primaire de la table sera renseignée automatiquement à partir d’une nouvelle séquence. Dans ce cas, il faut
renseigner le nom de la contrainte, le nom de la séquence et sélectionner la colonne de la table. Cliquez ensuite sur
le bouton Suivant >.
■ Cette page permet de définir des contraintes uniques ou CHECK. Pour créer une contrainte, vous devez spécifier
les caractéristiques de la contrainte, puis cliquer sur le bouton Ajouter. Dans l’exemple cidessus, il existe une
contrainte unique sur la colonne NOM. Après avoir défini les différentes contraintes, cliquez sur le bouton Fin ; une
page de confirmation s’affiche :
■ Pour afficher le code SQL correspondant à la création de la table, vous pouvez cliquer sur le lien SQL. Cliquez sur le
bouton Créer pour créer la table.
Vous pouvez procéder de la même manière pour créer la deuxième table de notre application :
Cette table comporte une clé étrangère vers la table COLLECTION que vous pouvez créer de la manière suivante :
3. Créer l’application
■ Sur la première page, saisissez le nom de votre application puis cliquez sur le bouton Suivant >.
■ Sur la deuxième page, vous allez pouvoir définir les premières pages de votre application. Pour commencer, nous
allons créer une page d’accueil : sélectionnez le type de page Vierge, saisissez le nom de la page ("Accueil" par
exemple) puis cliquez sur le bouton Ajouter une page.
■ Ensuite, nous allons créer une page pour saisir les données de la table COLLECTION directement dans un tableau.
Sélectionnez le type de page Panneau tabulaire, subordonnez la page à la page d’accueil, spécifiez la table
COLLECTION comme nom de table, puis cliquez sur le bouton Ajouter une page.
■ Pour terminer, pour saisir les données de la table LIVRE nous allons créer deux pages : une liste et un formulaire
de saisie. Sélectionnez le type de page Etat et panneau, subordonnez la page à la page d’accueil, spécifiez la table
LIVRE comme nom de table, puis cliquez sur le bouton Ajouter une page.
Vous devez maintenant avoir les pages suivantes dans votre application :
■ Cliquez sur le bouton Suivant >.
■ Cette page permet de structurer les onglets de l’application. Sélectionnez l’option Un niveau d’onglets puis cliquez
sur le bouton Suivant >.
■ Cette page permet de copier des composants partagés d’une autre application. Laissez l’option par défaut et
cliquez sur le bouton Suivant >.
■ Cette page permet de choisir le mode d’authentification à l’application et la langue de l’application. Sélectionnez le
mode d’authentification Application Express et la langue française, puis cliquez sur le bouton Suivant >.
Pour créer l’application, il ne reste plus qu’à cliquer sur le bouton Créer ; la page principale de l’éditeur de
l’application s’affiche :
Cette page propose différents outils qui permettront de personnaliser l’application.
L’application créée est opérationnelle ; nous allons pouvoir l’exécuter pour la tester.
4. Tester l’application
Pour exécuter l’application créée précédemment, il suffit de cliquer sur l’icône Exécuter l’application.
La page de connexion s’affiche :
Comme nous avons choisi le mode d’authentification Application Express pour cette application, il faut saisir ici le nom
et le mot de passe d’un utilisateur APEX ; le compte administrateur de l’espace de travail peut être utilisé.
Après connexion, la page d’accueil de l’application s’affiche :
Cette page permet de naviguer vers les autres pages de l’application.
■ Cliquez sur le lien COLLECTION pour afficher la page de saisie de la table COLLECTION :
■ Pour créer une nouvelle ligne, il suffit de cliquer sur le bouton Ajouter une ligne, de saisir les valeurs puis de
cliquer sur le bouton Soumettre :
■ Cliquez sur le lien Accueil en haut à gauche pour revenir sur la page d’accueil, puis sur le lien LIVRE pour accéder
à la page de gestion des livres. Cette page affiche la liste des livres ; pour l’instant, cette liste est vide :
■ Cliquez sur le bouton Créer pour créer un enregistrement :
■ Saisissez les différentes informations puis cliquez sur le bouton Créer pour enregistrer la saisie et revenir sur la
liste :
Comme vous pouvez le constater, cette application créée en quelques clics est parfaitement opérationnelle : elle
permet de consulter et saisir les informations des tables COLLECTION et LIVRE.
Par contre, l’interface utilisateur mériterait sans doute d’être améliorée ; c’est ce que nous allons faire au point
suivant.
5. Personnaliser l’application
Application Express propose un très grand nombre de fonctionnalités qui permettent de personnaliser les
applications. Dans ce point, nous présenterons quelques possibilités correspondant à des besoins courants :
● Modifier la présentation des pages.
● Créer et utiliser des listes de valeurs (statiques ou dynamiques).
● Ajouter des contrôles sur les données saisies.
a. Modifier la présentation des pages
■ Sur la page principale de l’éditeur, cliquez sur l’icône de la page que vous souhaitez modifier :
L’éditeur de page s’affiche :
■ Dans la région Eléments, cliquez sur l’icône de modification afin d’afficher une page permettant de
personnaliser les zones du formulaire :
Les différents onglets de cette page permettent notamment de modifier les libellés, la taille des zones ou d’associer
une petite aide à un élément.
À titre d’exemple, vous pouvez modifier les libellés, la largeur des zones et utiliser un modèle de champ qui indique
que le titre est obligatoire :
■ Cliquez sur le bouton Appliquer les modifications.
Pour modifier tous les attributs d’un élément, vous pouvez cliquer sur l’icône de modification associée à l’élément
.
La page qui s’affiche permet de modifier toutes les propriétés d’un élément : source de données, libellé, format
d’affichage, valeur par défaut, liste de valeur associée, etc.
Nous utiliserons cette page ultérieurement notamment pour associer une liste de valeurs à un champ. Cliquez sur le
bouton Annuler.
Pour visualiser le résultat des modifications, vous pouvez cliquer sur le bouton Exécuter de la page d’édition d’une
page.
Le formulaire de saisie doit maintenant avoir l’allure suivante :
Certains attributs peuvent être modifiés directement pendant la navigation dans l’application (sous réserve d’être
connecté avec un compte développeur). Pour cela, il faut d’abord afficher les liens d’édition en cliquant sur le lien
Afficher les liens de modification situé en bas à droite :
Ensuite, vous pouvez cliquer sur les icônes pour éditer les propriétés de l’élément associé.
Pour masquer les icônes d’édition, vous pouvez cliquer sur le lien Masquer les liens de modification situé en bas à
droite.
Pour revenir dans l’éditeur de la page, vous pouvez cliquer sur le lien Modifier une page N, N correspondant au
numéro de la page courante.
Nous allons maintenant modifier l’ordre des éléments dans le formulaire.
■ Cliquez sur l’icône de la zone Eléments. La page qui s’affiche permet de modifier la mise en page par
glisserdéplacer :
Dans la partie gauche, la structure actuelle de la page est affichée ; la position des différentes zones peut être
modifiée par glisserdéplacer. La partie droite propose plusieurs types de zones. Pour ajouter une nouvelle zone
dans la page, il suffit de glisserdéplacer l’icône correspondant au type de zone souhaité. Pour ajouter une nouvelle
ligne dans la page, vous pouvez glisserdéplacer le bouton Ajouter une ligne.
À titre d’exemple, nous allons déplacer la zone collection (P4_ID_COLLECTION) pour la positionner sous le soustitre
(zone P4_SOUS_TITRE). Pour cela, il faut d’abord insérer une ligne vide puis déplacer la zone.
Lorsqu’un élément est sélectionné, son libellé et son type peuvent être modifiés en haut de la page.
■ Lorsque les modifications sont terminées, cliquez sur le bouton Suivant > puis sur le bouton Appliquer les
modifications.
Vous pouvez ensuite exécuter la page pour visualiser les modifications.
b. Créer et utiliser des listes de valeurs
Pour faciliter la saisie des informations "collection" et "niveau", nous allons proposer des listes de valeurs à
l’utilisateur.
Dans l’éditeur de page, les listes de valeurs utilisées par la page sont affichées dans la zone Liste de valeurs
(LOV) située dans la colonne de droite (Composants partagés) :
■ Pour créer une nouvelle liste de valeurs, cliquez sur l’icône de création .
■ Sur la première page, laissez l’option Entièrement nouveau sélectionnée puis cliquez sur le bouton Suivant >.
■ Pour les différentes valeurs de niveau, nous allons utiliser une liste statique. Saisissez le nom de la liste de
valeurs, sélectionnez l’option Statique puis cliquez sur le bouton Suivant >.
Sur cette page, nous allons saisir les différentes valeurs de liste. APEX permet d’avoir une valeur retournée
différente de la valeur affichée (ce qui permet par exemple de stocker un code dans la base et non la valeur
affichée). Pour notre exemple, les valeurs retournées sont les mêmes que les valeurs affichées. Lorsque la saisie
est terminée, cliquez sur le bouton Créer une liste de valeurs (LOV) ; la page de gestion des listes de valeurs
s’affiche :
Une liste de valeur n’appartient pas à une page de l’application ; c’est un composant partagé qui peut être utilisé
dans plusieurs pages de l’application.
■ Sur la première page, laissez l’option Entièrement nouveau sélectionnée puis cliquez sur le bouton Suivant >.
■ Pour les différentes valeurs de collection, nous allons utiliser une liste dynamique, basée sur une requête SQL.
Saisissez le nom de la liste de valeurs, sélectionnez l’option Dynamique puis cliquez sur le bouton Suivant >.
Sur cette page, nous allons saisir la requête associée à la liste de valeurs. La clause SELECT de cette requête doit
comporter deux expressions : la première expression donne la valeur affichée dans la liste et la deuxième
expression la valeur retournée. Pour notre exemple, nous allons retourner le contenu de la table COLLECTION, avec
la colonne NOM comme valeur affichée et la colonne ID comme valeur retournée ; la liste est triée par ordre
alphabétique sur le nom. Lorsque la saisie est terminée, cliquez sur le bouton Créer une liste de valeurs (LOV) ; la
page de gestion des listes de valeurs s’affiche de nouveau.
Nous allons maintenant utiliser ces listes de valeurs dans notre formulaire de saisie des livres. Éditez la page
correspondante, puis cliquez sur le lien de l’élément P4_ID_COLLECTION pour éditer ces propriétés.
■ Dans l’éditeur des propriétés de l’élément, cliquez sur l’onglet Nom.
■ Sélectionnez la valeur Liste SELECT dans la liste Afficher en tant que.
■ Cliquez sur l’onglet Liste de valeurs (LOV).
■ Sélectionnez la liste de valeurs LISTE_COLLECTIONS et la valeur Oui dans la liste Afficher les valeurs Null. Dans
la zone Valeur d’affichage Null, saisissez la valeur aucune.
■ Cliquez sur le bouton Appliquer les modifications.
Nous allons faire la même chose pour le champ "niveau" (P4_NIVEAU), mais en optant pour un affichage en tant que
groupe de boutons d’option :
■ Sélectionnez la liste de valeurs LISTE_NIVEAUX. Dans la zone Nombre de colonnes, saisissez la valeur "4".
Cliquez sur le bouton Appliquer les modifications.
■ Exécutez la page pour visualiser le résultat :
c. Ajouter des contrôles sur les données saisies
APEX permet d’ajouter très facilement des contrôles sur les données saisies.
Dans l’éditeur de page, les contrôles sur les données saisies sont affichés dans la zone Validations située dans la
colonne du milieu (Traitement de page) :
■ Pour créer une nouvelle validation, cliquez sur l’icône de création .
■ APEX permet de définir des validations de niveau d’élément ou de niveau de page. À titre d’exemple, nous allons
créer une validation de niveau d’élément sur le nombre de pages. Sélectionnez l’option Validation de niveau
d’élément et cliquez sur le bouton Suivant >.
■ Sélectionnez l’élément correspondant au nombre de pages et cliquez sur le bouton Suivant >.
■ Sélectionnez SQL comme méthode de validation et cliquez sur le bouton Suivant >.
■ Sélectionnez Expression SQL comme type de validation et cliquez sur le bouton Suivant >.
■ Indiquez le nom de la validation, sélectionnez le mode d’affichage du message d’erreur et cliquez sur le bouton
Suivant >.
■ Saisissez ensuite l’expression SQL permettant de valider l’élément et le message d’erreur associé. Dans
l’expression SQL, vous pouvez faire référence aux éléments de la page en faisant précéder le nom de l’élément
par le caractère ":". Cliquez sur le bouton Suivant >.
■ La dernière page permet de préciser dans quels cas la validation doit être contrôlée. Dans la liste déroulante
Type de condition, sélectionnez la valeur La demande est contenue dans Expression 1, puis saisissez "SAVE,
CREATE" dans la zone Expression 1.
■ Cliquez sur le bouton Créer pour créer la validation.