TP-SI-BD II (Oracle)

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 21

cheikh.ba.sn@gmail.

com

SI - Bases de Données II
TP - Oracle
1 Environnement de Travail
L’objectif de cette session de TP est de manipuler le SGBDR Oracle en se basant sur un client
en mode ligne de commande CLI (Command Line Interface), en l’occurence SQL*Plus, ou sur un
environnement plus évolué et plus ergonomique (Oracle SQL Developer). Oracle Database
XE (Oracle Database Express Edition), la version gratuite et limitée (à 4Go de données) de Oracle,
est installé sur une machine virtuelle dont vous disposerez.

• Pourquoi Oracle ?
Il est dans le programme de cette année, et il a fini de faire ses preuves.

• Pourquoi une machine virtuelle ?


Pour vous faire découvrir le principe de virtualisation, un Système d’Exploitation Linux, et
pour vous épargner les problèmes d’installation, les TP se feront avec Oracle XE installé sur
un Ubuntu virtualisé (dans Windows ou Linux). Vous n’avez pas besoin d’être un expert en
Linux pour ce TP. Voici juste quelques commandes qui peuvent s’avérer utiles.

% ls -l // Liste les fichiers du répertoire courant


% pwd // Nom du répertoire courant
% cd rep // Se positionne dans le répertoire ’rep’
% cd // Ramène au répertoire de départ
% cp source cible // Copie le fichier source vers le fichier cible.
% mv source cible // Renomme le fichier ’source’ en fichier ’cible’
% gedit & // Lance l’éditeur de texte gedit en t^
ache de fond

Bien sûr, toutes ces commandes peuvent être réalisées en utilisant tout simplement l’environnement
graphique (explorateur de dossiers).

La virtualisation permet de simuler, à l’aide d’un logiciel, appelé superviseur ou hyperviseur,


une machine physique (disque dur, RAM, OS, ...). Il existe plusieurs logiciels pour la virtu-
alisation (VMWare, VirtualBox, VirtualPC, ...), et nous choisirons VirtualBox (de Oracle).

1
1.1 Installation du superviseur ’Oracle VM VirtualBox’:
Sous Windows, il vous suffit de lancer "VirtualBox-4.1.14-77440-Win.exe", et de suivre les
instructions. Sous Linux, cela dépendra de votre distribution.

1.2 Création d’une machine virtuelle Ubuntu.


Ce travail vous est épargné. Une machine "ubuntu-10.4-Oracle-xe-SqlDev-3.1.vdi" est déjà
créée. Il ne vous reste qu’à le dire au superviseur, après avoir copié le disque dur de la machine
(que l’on confond à la machine elle même) dans un répertoire (en général le répertoire contenant
les disques de VirtualBox ). Je vous montrerai la marche à suivre. Vous pouvez maintenant lancer
la machine et découvrir le Système d’Exploitation Ubuntu (pour ceux qui ne l’ont jamais vu).

− Votre identifiant pour Ubuntu : etudiant

− Votre mot de passe : ubuntu

1.3 Installation de ’Oracle Database Express Edition’ et outils connexes


Ceci vous a aussi été épargné. Oracle XE est déjà installé sur la machine virtuelle, ainsi de que
d’autres outils connexes: Oracle SQL Developer, SQL*Plus, SQL Loader, etc.

1.3.1 Oracle XE
• Lancement et arrêt du serveur de base de données: Le système est configuré de telle sorte
que le serveur Oracle XE est lancé à chaque démarrage de la machine Linux.

– Lancement et arrêt en mode console (commande):

# sudo /etc/init.d/oracle-xe start % Pour le lancement


# sudo /etc/init.d/oracle-xe stop % Pour l’arr^et
# sudo /etc/init.d/oracle-xe status % Pour vérification

– Lancement et arrêt en utilisant l’environnement graphique du bureau Ubuntu:


Menu: Applications -> Oracle Database 10g Express Edition -> Start Database
Menu: Applications -> Oracle Database 10g Express Edition -> Stop Database

Le serveur de base données Oracle XE (Oracle Database Listener ) écoute sur le port 1521.

• Informations importantes:
(1) Après installation, il existe par défaut un certain nombre de comptes utilisateurs automa-
tiquement créés:

– Comptes SYSTEM et SYS, mot de passe ubuntu: ce sont des comptes systèmes. Vous
aurez à utiliser le compte SYSTEM pour la création de l’utilisateur etudiant.
– Compte HR, mot de passe hr: compte utilisateur, avec une base de données exemple
(Human Ressources ou Ressources Humaines). Ce compte est bloqué par défaut, mais
il a été déverrouillé. Vous pourrez l’utiliser pour vos premières requêtes.

2
(2) APEX (Oracle Application Express): Si le serveur est lancé, il existe une application
web, écoutant sur le port 8080, et permettant l’administration et le développement rapide
d’applications web pour oracle. Cette application est accessible à l’adresse

http://localhost:8080/apex

Vous pourrez l’utiliser pour créer et administrer de nouveaux comptes utilisateurs, en vous y
connectant en tant que SYSTEM (mot de passe ubuntu). Vous pouvez aussi vous y connecter
comme utilisateur HR (mot de passe hr) et voir des informations sur sa base exemple.

1.3.2 SQL*Plus
C’est un outil en ligne de commande permettant la manipulation (instructions SQL) des tables et
autres objets dans une base de données Oracle.

• Entrée et sortie en mode console (commande) ou terminal:

# sqlplus % Le système vous invite à saisir un login et mot de passe


%% == OU ==
# sqlplus user/password % ’user’ et ’passwd’ étant ceux d’un compte valide

#SQL> disconnect % pour se déconnecter


#SQL> quit % ou ’exit’ pour quitter SQL*Plus

• Entrée en utilisant l’environnement graphique du bureau Ubuntu:

Applications -> Oracle Database 10g Express Edition -> Run SQL Command Line

• Remarques sur la saisie de commandes

− Toutes les commandes SQL doivent se terminer par ’;’. Si vous oubliez le ’;’, une ligne
’2’ vous est proposée. Dans ce cas tapez un ’;’ pour finir la commande.
− Les chaı̂nes de caractères s’écrivent avec une simple quote : ’Vertigo’ et pas ”Vertigo”.
− Les majuscules et les minuscules sont interprétés différemment. Par exemple ’Vertigo’ est
considéré comme différent de ’vertigo’ ou ’VERTIGO’. Pensez-y en faisant des sélections.
Un moyen d’éviter les problèmes est d’utiliser la fonctions UPPER qui met tout en ma-
juscule. Par exemple :

SELECT * FROM film WHERE UPPER(titre) = ’VERTIGO’;

1.3.3 Oracle SQL Developer


C’est un outil destiné d’abord à la programmation en PL/SQL de fonctions, procédures et packages,
mais qui permet également de visualiser et agir sur les objets Oracle, avec une interface graphique
beaucoup plus conviviale: explorateur d’objets, éditeur de requêtes en mode texte (avec une col-
oration syntaxique et une complétion de texte) et en mode graphique (Graphical Query Builder ).
Pour le lancer, on peut utiliser le menu :

3
Menu: Applications -> Programming -> SQL Developer

Il faut bien évidemment vous connecter (avec login et mot de passe) à une base existante avant de
pouvoir faire des manipulations. Ci-dessous, un exemple de connexion de l’utilisateur HR.

1.3.4 SQL Loader


C’est un outil (en mode commande) permettant de charger des données situées dans des fichiers
externes vers la base de données Oracle. Nous verrons plus loin comment le lancer et comment
charger des données.

2 Étude du dictionnaire de données Oracle


2.1 Rappels
Oracle dispose d’une structure centralisée (le dictionnaire de données) contenant la description de
tous les objets (tables, vues, utilisateurs, ...) gérés par ce SGBD. Ce dictionnaire regroupe donc
toutes les informations nécessaires au fonctionnement du SGBD. Il présente la particularité d’être
lui-même organisé comme une base de données (on parle de meta-base) et d’être par conséquent
accessible directement à travers SQL. Pour des raisons d’intégrité aisément compréhensibles, la
plupart des tables du dictionnaire ne sont pas modifiables par les utilisateurs (seul l’administrateur
a accès à ces dernières). A l’opposé, l’accès en lecture à leur contenu est généralement autorisé,
ce qui va nous permettre d’explorer quelque peu le dictionnaire afin de mieux appréhender cette
structure de donnée essentielle au SGBD.
D’une manière plus précise, les tables du dictionnaire sont généralement cryptées. Leur contenu
est par contre accessible par l’intermédiaire de ”vues”. Elles sont de quatre grands types:

• Vues relatives aux objets d’un utilisateur : USER *


• Vues relatives aux objets accessibles à un utilisateur: ALL *
• Vues relatives aux administrateurs: DBA *

• Vues relatives aux suivi des performances: V$*

Au cours de ce TP, nous allons nous intéresser plus particulièrement aux vues de type ALL et USER.

4
2.2 Organisation générale du dictionnaire
Dans un premier temps, nous allons étudier l’organisation du dictionnaire de données Oracle.
L’ensemble des tables du dictionnaire de données est recensé dans la table principale DICT.
Connectez-vous à la base en tant que l’utilisateur "HR":

Compte: hr
Mot de passe: hr

2.2.1 Vues relatives aux objets accessibles à tous les utilisateurs


1. Donner le schéma de la relation correspondant à DICT et préciser le rôle de chacun de ses
attributs. On utilisera pour cela la commande SQL de description DESCRIBE (ou DESC).

2. Visualiser le contenu complet du dictionnaire DICT à l’aide de la commande de sélection


SELECT.

3. Donner le rôle et la structure des tables (ou vues) suivantes : ALL CATALOG, ALL TAB COMMENTS,
ALL USERS, ALL COL COMMENTS, et ALL TAB PRIVS, ALL TRIGGERS. En vous aidant le cas échéant
du contenu de la table ALL COL COMMENTS ou de la documentation Oracle; donner succincte-
ment le rôle de chaque attribut de ces tables.

4. Quels sont les différents types d’objets standards (attribut TABLE TYPE) reconnus par Oracle
dans son catalogue ? A quelles tables du dictionnaire correspondent ces différents types ?

5. Combien y-a-t-il d’objets référencés dans la table ALL CATALOG. Comparer ce résultat avec la
somme du nombre d’enregistrements dans les tables ALL TABLES, ALL VIEWS, ALL SYNONYMS,
ALL SEQUENCES. Observez-vous une différence ? Si oui, pouvez vous l’expliquer ?

2.2.2 Vues relatives aux objets d’un utilisateur


1. Donner le rôle et le schéma de relation correspondant à la table USER USERS. Quel est votre
nom d’utilisateur Oracle ?

2. Comparer le contenu des tables ALL CATALOG et USER CATALOG. Commentaires ?

2.2.3 Structure d’une base de données existante


Nous allons maintenant utiliser le dictionnaire de données pour retrouver la structure d’une base
de données existante.

1. Existe-t-il des objets de nom EMPLOYEES dans la base ? Quels sont leurs types ?

2. Nous considérerons maintenant uniquement l’objet de type table. Quel est le propriétaire de
la table EMPLOYEES ?

3. Chercher l’ensemble des tables ayant même propriétaire que EMPLOYEES : vous devriez récupérer,
entre autres, l’ensemble des tables de la base de données que nous étudions.

5
4. Quelles sont les contraintes d’intégrité (CONSTRAINT NAME) associées à la table EMPLOYEES.
Quel est le type (clé primaire, contrainte d’intégrité référentielle...) de chacune d’elles.
Pour les contraintes d’intégrité référentielle, donner le nom de la contrainte correspondante
(R CONSTRAINT NAME) dans la table référence, et donner cette table référence.

5. Quel est le nom de la contrainte de clé primaire associée à la table JOB HISTORY ? Quelle
est la clé primaire de cette table1 ? Vous devriez découvrir une table du dictionnaire et la
manière dont cette information est stockée.

6. En analysant de même les contraintes associées aux autres tables2 , retrouver la structure de
la base de données (schémas de relation avec les attributs, clés primaires, clés étrangères avec
la table et l’attribut référencé) formée par les tables trouvées à la question 3.

7. En déduire un modèle Entité/Association (notation UML avec spécification des clés primaires
et des cardinalités) correspondant au schéma de relation précédemment trouvé, en justifiant
chacune des cardinalités (une seule justification par type de cardinalité3 , en fournissant à
chaque fois une requête de confirmation).

3 Création d’une BD Oracle


On considère une base de données regroupant différentes informations sur des hommes politiques
français, et en particulier leurs cotes de popularité estimées par différents instituts de sondages.
Soient donc les relations suivantes :

PERSONNE (num_h, nom, prenom, parti, fonction) % liste des hommes politiques
INSTITUT (sigle, courant) % liste des instituts de sondages
PARTI (num_p, sigle, nom, courant) % liste des partis
SONDAGE (institut, n_hom, cote, date_s) % listes des c^
otes de popularité

Ces relations sont définies dans les tableaux suivants. À vous de déterminer les attributs jouant le
rôle de clés primaires ou à les rajouter le cas échéant, de même que les relations entre tables donnant
lieu à une intégrité référentielle. Pour cela, on donne la définition des dépendances fonctionnelles
correspondant à cette BD:

Relation PERSONNE num_h --> nom, prenom, parti, fonction


Relation INSTITUT sigle --> courant
Relation PARTI num_p --> sigle, nom, courant
Relation SONDAGE institut, n_hom, date_s --> cote

On donne de même les dépendances d’inclusion correspondantes:

Πparti (P ERSON N E) ⊆ Πnum p (P ART I)

Πinstitut (SON DAGE) ⊆ Πsigle (IN ST IT U T )


1
Cette information ne se trouve pas dans la table ALL CONSTRAINTS
2
Vous n’avez pas besoin de redonner les requêtes pour les autres tables.
3
Types de cardinalité: 0..1, 1..1, 0..n et 1..n

6
Πn hom (SON DAGE) ⊆ Πnum h (P ERSON N E)

PERSONNE Attribut Définition


num h Référence de l’homme politique, entier
nom Nom de la personne, chaı̂ne de 30 caractères, renseigné
prenom Prénom de la personne, chaı̂ne de 20 caractères, renseigné
parti Référence au parti auquel appartient la personne
fonction Fonction (ministre, etc.) assurée, chaı̂ne de 20 caractères

INSTITUT Attribut Définition


sigle Sigle de l’institut, chaı̂ne de 10 caractères, renseigné
courant Orientation politique de l’institut, chaı̂ne de 20 caractères

PARTI Attribut Définition


num p Référence de parti, entier positif
sigle Sigle du parti, chaı̂ne de 10 caractères, renseigné
nom Nom du parti, chaı̂ne de 30 caractères, renseigné
courant Orientation politique du parti, chaı̂ne de 20 caractères, renseigné

SONDAGE Attribut Définition


institut Référence à l’institut de sondage
n hom Référence à la personne concernée
cote Cote de popularité (% compris entre 0 et 100), entier, renseigné
date s Date du sondage, date, renseigné

3.1 Création du schéma de la base de données sur les sondages


1. Déterminez l’ensemble des clés primaires et étrangères de la base de données. Dans quel ordre
devront nécessairement être créées vos relations ?

2. Écrire sur papier les requêtes SQL de création des relations PARTI et PERSONNE. Faites valider
ce schéma conceptuel et ces requêtes par votre enseignant. Si tout va bien, vous pouvez alors
vous connecter à Oracle pour réaliser le TP proprement dit:

• Création de l’utilisateur etudiant4, avec comme mot de passe ubuntu:


(a) Allez sur le site de APEX5 : http://localhost:8080/apex
(b) Connectez-vous en tant que utilisateur SYSTEM, le mot de passe est ubuntu
(c) Cliquez sur "Administration", puis "Database Users" et enfin sur "Create >"
(d) Renseignement des champs:
** Create Database User **
Username: etudiant
Password: ubuntu
Confirm Password: ubuntu
Expire Password: Ne pas cocher
4
Création d’un nouvel utilisateur avec sa base.
5
Notez bien que ceci est tout aussi faisable en ligne de commande avec la commande SQL CREATE USER ...

7
** User Privileges **
% Tout cocher sauf sur DBA ! (vous pouvez cliquer sur "Check All")
(e) Cliquez sur "Create"
(f) Déconnectez l’utilisateur SYSTEM en cliquant sur "Logout"
(g) Retournez sous SQL*Plus ou SQL Developer et connectez-vous en tant que "etudiant"
– Sous SQL Developer, il voudra bien sûr créer une nouvelle connexion.
3. Créez sous Oracle l’ensemble des relations de votre base de données, en tenant compte de
l’ensemble des contraintes d’intégrités.
4. A l’aide de l’ordre SQL COMMENT ON, documentez les différents objets de votre base de données.
5. A l’aide de la commande DESCRIBE, vérifiez que les relations de la base de données ont bien été
créées dans leur ensemble. Cette vérification de base ne vous assure pas de la bonne création
des contraintes d’intégrité, ou de la mise en position des commentaires. Vérifiez l’existence
de tout cela en parcourant le dictionnaire Oracle pour les objets vous concernant.

3.2 Chargement de la base de données: SQL*Loader


1. A l’aide de la clause SQL INSERT INTO, remplissez la table INSTITUT avec les données:

sigle courant
IFOP
IPSOS droite
BVA
SOFRES gauche

Il est possible de remplir une relation en important des données à partir d’un fichier externe.
On utilise pour cela l’utilitaire Oracle SQL*Loader (commande sqlldr) présenté en cours.
2. En utilisant SQL*Loader, remplissez la table PARTI avec les données du fichier parti.don.
Créez pour cela le fichier de contrôle parti.ctl correspondant. Pour rappel, une syntaxe de
chargement possible est :

sqlldr userid=USER/PASSWD control=’parti.ctl’

Pour une aide sur la commande, saisir sqlldr sans paramètre.


3. Tous les éléments du fichier de données ont-ils pu être chargés ? Le cas échéant, quels sont
les éléments qui ont posé problème et pourquoi ? Consultez les fichiers de log générés.
4. Les données correspondant à la table PERSONNE sont dans le fichier pers.don. Créez un fichier
de contrôle pers.ctl pour permettre l’insertion de ces données à l’aide de SQL*Loader (sans
l’instruction TRAILING NULLCOLS).
5. Cette fois, quels sont les éléments qui n’ont pu être chargés ? Quel est la cause des problèmes
rencontrés ? Remédiez à cela en vous limitant au seul fichier de contrôle pers.ctl. Y-a-t-il
un nouveau problème ? Pourquoi ?

8
6. La dernière solution consiste à réaliser un fichier de commande regroupant un ensemble de
requêtes SQL d’insertion de tuples (pouvant avoir été générées par un script). Le fichier de
commande sondages.sql regroupe les commandes nécessaires au remplissage de la dernière
table. Après l’avoir consulté, exécuter ce fichier à l’aide de la commande start6 (ou @).

7. Les dernières élections régionales ont vu l’apparition de partis plus ou moins folkloriques
qu’il faut bien rentrer dans notre base de données. Pour cela, on dispose d’un fichier nou-
veau parti.don. À l’aide de SQL*Loader, rajoutez les données correspondantes à votre base
de données (table parti), sans écraser les données précédentes.

8. Cherchez enfin à charger dans la table PERSONNE les données contenues dans bad pers.don,
correspondant au fichier de contrôle bad pers.ctl. Le chargement des données pose problème.
En consultant les fichiers de log générés par SQL*Loader, détaillez les erreurs rencontrées.

9. Intéressons-nous maintenant à la ligne < 3, Besancenot, Olivier, 3, > du fichier pers.don,


dont l’insertion dans la table PERSONNE a été rejetée (Question 4).

(a) Réessayez de l’insérer à nouveau, avec l’instruction INSERT cette fois-ci, et revoir le
message d’erreur. Quel est le nom de la contrainte d’intégrité qui pose problème ?
(b) Désactivez cette contrainte d’intégrité (commande ALTER TABLE ..., cf Cours)
(c) Réessayez l’insertion du tuple. Résultat ?
(d) Essayez de réactiver la contrainte d’intégrité, sans l’option NOVALIDATE. Résultat ?
(e) Essayez maintenant de le faire avec l’option NOVALIDATE. Résultat ?
(f) Quel est le ROWID du tuple ”ancien” ne respectant pas la contrainte ?

4 Vues: définition, manipulation ...


1. Créer une vue V GVT qui garde tous les attributs de la table PERSONNE et qui donne la liste
des ministres de la base de données. On définira la vue avec l’option de vérification des
contraintes sur modification (WITH CHECK OPTION). Vérifiez dans le dictionnaire Oracle que
cette vue a correctement été créée.

2. Jouez avec cette vue V GVT : modifiez, ajoutez et supprimez des tuples dans la vue, puis allez
voir le contenu de la table entrant dans la définition de la vue. Commentaires ?

3. Si vous ne l’avez pas encore fait, essayer d’insérer dans votre vue un tuple correspondant à
un homme politique qui n’est pas ministre. Commentaires ?

4. Modifiez la vue pour la définir sans l’option de vérification et rejouer le cas précédent : que
se passe-t-il (dans la table d’origine et dans la vue) ?

5. Les informations nécessaires à la cohérence de la base de données (clé primaire par exem-
ple) n’ont pas à être connues d’un utilisateur lambda. Les vues permettent précisément
de n’afficher que l’information utile aux utilisateurs. Supprimez donc votre vue V GVT puis
6
Après l’avoir lancée sur SQL*Plus, n’oubliez pas de faire un commit si toutefois vous voulez faire des vérifications
sous SQL Developer.

9
recréez-là gardant tous les attributs de la table PERSONNE à l’exception de la clé primaire
num h, et sans définir l’option de vérification des contraintes de définition de la vue. Jouez à
nouveau avec votre vue : quelles observations faites-vous ?

6. Supprimez une nouvelle fois votre vue V GVT puis recréez-là en gardant cette fois, outre la clé
primaire, uniquement les attributs nom et prenom de la table personne. Quelle observation,
sur les données de PERSONNE et de V GVT, faites-vous en jouant avec la vue ?

7. Afin d’éviter à avoir à préciser des relations de jointures dans les requêtes de sélection multi-
tables, il peut sembler intéressant de créer une vue réalisant la jointure des tables concernées.
Créer ainsi une vue V COTES qui donne directement la cote de popularité (cote, institut,
date) de chaque homme politique (nom, prenom, sigle du parti).

8. De même, jouez avec cette vue V COTES. Quelles observations pouvez-vous faire ?

5 Vues concrètes ou vues matérialisées ou snapshots


1. Créez maintenant deux vues matérialisées CLICHE HEBDO GVT et CLICHE LIVE GVT répondant
à la même définition que la vue V GVT et dont la mise à jour se fait respectivement de manière
hebdomadaire ou sur une validation (COMMIT). La mise à jour de ces vues concrètes se fera
par chargement complet des données. Vérifiez la bonne création de ces vues concrètes dans
le dictionnaire Oracle.

2. Ajoutez le tuple (<valeur cle>, ’Delanoe’, ’Bertrand’, <id parti>, ’ministre’) à


la table PERSONNE. Consultez le contenu de la vue V GVT et des vues concrètes CLICHE HEBDO GVT
et CLICHE LIVE GVT . Quels commentaires pouvez-vous faire ?

3. Validez maintenant l’insertion précédente (COMMIT). Réitérez l’exploration du contenu des


différentes vues : conclusion ?

4. Tentez maintenant de créer une vue concrète CLICHE QUOTIDIEN GVT équivalente à renou-
vellement journalier suivant un mode incrémental de mise à jour. Quelle réaction d’Oracle ?
Savez-vous expliquer cette situation ?

6 Synonymes
1. Créez un synonyme S PERSONNE <VOTRE NOM> à partir de la table PERSONNE. Vérifiez dans le
dictionnaire de données qu’il a bien été créé. Jouez avec ce synonyme : est-il possible de
modifier le contenu de la table à travers ce synonyme ?

2. Ce synonyme est-il visible de la part des autres utilisateurs Oracle ? Comment est-il déclaré
dans le dictionnaire de données ?

3. Est-il possible de créer un synonyme public V GVT <VOTRE NOM> à partir de la vue V GVT ? Si
oui, est-ce-que ce synonyme est visible par les autres utilisateurs ? Qui est le propriétaire de
cette vue publique ?

10
7 Privilèges objets et système
Transparence de la vie politique oblige, on souhaiterait accorder à tous les utilisateurs le droit
de consulter le contenu de la table PERSONNE, ou plus précisément les informations concernant les
ministres.

1. Dans un premier temps, on se contente d’accorder des droits en lecture sur la table PERSONNE.
Donnez ce privilège à l’ensemble des utilisateurs. Vérifiez dans le dictionnaire que ce droit a
bien été accordé (ALL TAB PRIVS). En pratique, les autres utilisateurs (comme HR) peuvent-ils
bien accéder au contenu de cette table ?

On voudrait maintenant limiter ce droit de lecture aux seuls hommes politiques occupant une
fonction de ministre. L’idée est donc d’accorder un droit de lecture uniquement sur la vue
V GVT.

2. Révoquez les droits de lecture que vous venez de définir sur la table PERSONNE. Vérifiez que
ces droits sont bien supprimés et qu’il n’est plus possible d’accéder à votre table.

3. Limitez maintenant les droits de lecture à la vue V GVT et vérifiez que ce privilège est bien
opérationnel.

4. Sans jouer sur les privilèges, une dernière solution consiste à passer par la création d’un
synonyme public bien choisi. Vérifiez tout d’abord dans le dictionnaire Oracle que vous
disposez du privilège système correspondant. Si oui, créez ce synonyme publique et vérifiez
qu’ainsi les informations sur tous les ministres sont bien visibles des autres utilisateurs. Qui
est le propriétaire de cette vue publique ?

8 Transactions
Nous allons maintenant étudier la gestion de transaction en SQL.

1. Validez (commit) tout d’abord vos dernières actions en fermant la transaction courante.

2. Dans la table PARTI, ajoutez le tuple (”LNJ”, ”Ligue des Nains de Jardin”, ”ExtGauche”).
Consultez le contenu la table puis annulez (rollback) cette transaction. Quelle observation
faites-vous en consultant à nouveau le contenu de la table.

3. Refaites la même opération, mais validez la transaction avant de faire une annulation. Con-
clusion ?

4. Dans la table PARTI, ajoutez le tuple (”SS”, ”Sologne aux Solognots”, ”ExtDroite”). Puis
ajoutez un attribut naissance, de type DATE, à cette table. Annulez cette transaction puis
consultez la structure et le contenu de la relation. Quelle observation faites-vous ? Pouvez-
vous expliquer ce résultat ?

5. Pour finir, connectez vous à la base, une deuxième fois, avec un autre client7 .

(a) Insérer un tuple dans la table PARTI avec l’un des clients, sans valider la transaction.
7
Si vous utilisez SQL*Plus, connectez vous avec SQLDeveloper, ou vice versa

11
(b) Essayer d’insérer le même tuple avec l’autre client. L’insertion a-t-elle été possible ?
y-a-t-il un verrouillage ? Pourquoi ?
(c) Validez ou annuler la première insertion. Que se passe-t-il avec la deuxième ?

9 PL/SQL: Procedural Language SQL


9.1 Création d’une instance de BD: tables CLIENT, PRODUIT, FOURNISSEUR et COMMANDE
1. Créer un nouvel utilisateur (utiliser APEX). Login / Mot de passe: plsql / plsql.

2. Créer le schéma de la base de données suivant (fichier plsql-schema-ventes.sql disponible):

# CLIENT : id_client : chaine de caractère (4) non null # Clé


nom_client : chaine de caractère (30)
date_client : date

# FOURNISSEUR : id_fournisseur : chaine de caractère (4) non null # Clé


nom_fournisseur : chaine de caractère (30)
ville : chaine de caractère (30)
date_fournisseur : date

# PRODUIT : id_produit : chaine de caractère (4) non null # Clé


id_fournisseur : chaine de caractère (4) non null # Clé étrangère ==> FOURNISS.
libelle_produit : chaine de caractère (20)
type_produit : chaine de caractère (20)
qte_stock : numerique (positif)
qte_alerte : numerique (positif)

# COMMANDE : id_client : chaine de caractère (4) # Élém. Clé prim. Clé étr. ==> CLIENT
id_produit : chaine de caractère (4) # Élém. Clé prim. Clé étr. ==> PRODUIT
quantite : numerique (positif)
date_cmd : date

3. Créer l’instance de la base de données suivante (fichier plsql-base-ventes.sql disponible):

# CLIENT : # FOURNISSEUR :
("c001","Dupont",29/03/04); ("f001","Danone","Paris",05/07/02);
("c002","Delannoy",09/10/03); ("f002","Poulin","Blois",03/12/01);
("c003","Serrano",12/06/04); ("f003","Charal","Orleans",05/07/02);
("c004","Robida",07/07/04);
("c005","Lebars",01/01/05);

# PRODUIT : # COMMANDE :
("p001","f001","yaghourt","laitier",100,5); ("c001","p005",10, 20/03/05);
("p002","f001","lait","laitier",85,5); ("c001","p004",10, 22/03/05);
("p003","f002","Chocolat78","Chocolatier",200,100); ("c003","p003",15, 25/03/05);
("p004","f003","Steak","charcuterie",75,5); ("c005","p002",10, 20/03/05);
("p005","f003","filet","charcuterie",70,5);

12
9.2 Rappel de la structure d’un code PL/SQL
####################### Sous SQL*Plus ############################
# SQL> DECLARE #
# 2 -- ensemble de délarations de variables; #
# 3 -- de consantes, d’exceptions et de curseurs; #
# 4 BEGIN #
# 5 -- instructions SQL, PL/SQL, structures de contr^
ole; #
# 6 EXCEPTION #
# 7 -- traitement des erreurs; #
# 8 END; #
# 9 / #
##################################################################

9.3 Généralités: variables et valorisation, boucles, types de données


## NB ##
# SQL> SET SERVEROUTPUT ON # Activation de la sortie écran de SQL*Plus pour PL/SQL
# DBMS_OUTPUT.PUT_LINE() # Affichage.
########

1. Tester l’effet du programme suivant (faire les vérifications nécessaires):

DECLARE
x NUMBER := 1;
BEGIN
WHILE (x < 85) LOOP -- Boucle pas très utile !
DELETE FROM PRODUIT WHERE qte_stock = 100;
x := x + 2;
END LOOP;
END;
/

Annuler l’effet de ce programme par la commande ROLLBACK;

2. Variable définie dans un environnement extérieur à un bloc PL/SQL.

SQL> variable x NUMBER


SQL> define t = PRODUIT
SQL> BEGIN
SELECT COUNT(*) INTO :x from &t;
END;
/

Il faut remarquer:

• Les définitions externes (variable et define)


• Les référencements internes (: et &)
• La valorisation (affectation) à partir d’une requête (INTO)
Afficher, hors du bloc PL/SQL, le contenu de x avec la commande PRINT.

SQL> print x

13
3. Faire de même que précédemment en affichant, dans le bloc PL/SQL, la valeur de x, précédée
du texte ’Le nombre de tuples dans la table est: ’.

4. Déclarer une variable de type RECORD contenant les mêmes attributs (donc les mêmes types)
que la table COMMANDE (en utilisant le type référence %TYPE). Remplir la variable par le tuple
dont le champ Quantite = 15 puis afficher le résultat.

5. Faire la même chose en utilisant cette fois ci une variable de type ligne (%ROWTYPE).

6. Que fait la commande SELECT SYSDATE FROM DUAL ? Faire un bloc PL/SQL qui fait pareil.

9.4 Curseurs
1. Créer deux variable externes v id client et v nom client de types correspondant à CLIENT

• Faire un bloc PL/SQL et déclarer un curseur c cli sur la table CLIENT


• Utiliser une série de FETCH pour le parcours
• Afficher l’id et le nom du dernier client lu dans la table.

2. Faire la même chose que précédemment, mais en utilisant la syntaxe:

FOR variable IN curseur LOOP -- c’est ce qu’on appelle un FETCH implicite !


-- instructions..
END LOOP

3. Que fait le bloc suivant ?

DECLARE
CURSOR C1 is SELECT * FROM COMMANDE
FOR UPDATE OF QUANTITE;
CMD C1%ROWTYPE;
BEGIN
Open C1;
fetch C1 into CMD;

while C1%FOUND loop


update COMMANDE set QUANTITE = CMD.QUANTITE - 1
where current of C1;
fetch C1 into CMD;
end loop;
commit;
close C1;
END;
/

• L’instruction FOR UPDATE OF ... sert à réserver les lignes lors de la création du curseur
par un verrou d’intention. Elle peut être absente, mais les conséquences peuvent être
non négligeables ...

4. Que fait la commande suivante ?

14
SQL> SELECT id_client, nom_client
FROM client
WHERE ROWNUM <= 3;

Créer un curseur avec paramètre (entier n) permettant d’afficher les n premières lignes de la
table CLIENT dans un bloc PL/SQL. Essayer de le faire avec les deux méthodes de parcours
(avec FETCH et avec FOR..IN).

############# Syntaxe curseur paramétré #############


# CURSOR nom_curseur (nom_param1 type_donnée1, ...) #
# IS requ^
ete_SELECT; #
#####################################################

9.5 Exceptions
1. Essayer le code suivant :

DECLARE
vnom client.nom_client%type;
BEGIN
SELECT nom_client INTO vnom FROM client;
dbms_output.put_line(’Pas d’’exception levée par la commande SELECT’);
EXCEPTION
when TOO_MANY_ROWS then
dbms_output.put_line(’Exception: trop de lignes pour une variable de type ligne !’);
END;
/

Ajouter la clause WHERE id client = ’c001’ à la requête SELECT précédente. Qu’est ce qui
s’est passé ?

2. L’exception TOO MANY ROWS est une exception prédéfinie (parmi tant d’autres8 ). Un utilisateur
peut définir ses propres exceptions en précisant leurs noms suivis du mot clé EXCEPTION dans
la partie DECLARE. Ensuite, il lui restera à définir des conditions pour lesquelles les exceptions
devront être levées par la commande RAISE. La syntaxe est la suivante :

DECLARE
...
mon_exception EXCEPTION;
...
BEGIN
...
IF (anomalie) THEN RAISE mon_exception;
...
END IF;
EXCEPTION
...
WHEN mon_exception THEN (traitements);
END;
/
8
ZERO DIVIDE, NOT LOGGED ON, NO DATA FOUND, CURSOR ALREADY OPEN, ...

15
Créer une exception qui se lance quand on tombe sur le nom ”Robida” lors du parcours
de la table CLIENT. Pour la gestion de l’exception, afficher juste le message ’Robida trouvé,
exception lancée’.
3. Mettre le bloc de la question 1 dans un bloc père (imbrication), où vous déclarerez et gérerez
(en affichant juste un message) une exception qui s’appelle ”trop de lignes”. Quant à la
gestion de l’exception du sous bloc (TOO MANY ROWS), propager l’exception vers le bloc père
(en levant l’exception ”trop de lignes”) avant d’afficher le message ”Exception : trop de
lignes à mettre ...”.
Ce massage s’affiche-t-il au lancement du bloc ? Pourquoi ?
4. Exécuter le code suivant et essayer de comprendre :
BEGIN
DECLARE
vnom client.nom_client%type;
BEGIN
select nom_client into vnom from client;
dbms_output.put_line(’Pas d’’exception levée par la commande SELECT’);
EXCEPTION
WHEN TOO_MANY_ROWS
then Raise_application_error(-20011, ’Beaucoup trop de lignes ! ’);
END;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(’Code: ’ || SQLCODE || ’, Message: ’ || SQLERRM);
END;
/

La procédure RAISE APPLICATION ERROR permet de définir ses propres messages et codes
d’erreurs. La valeur du code définie par l’utilisateur pour l’exception doit être comprise entre
-20000 et -20999.
5. Faire de même pour le code suivant (4 essais) en :

DECLARE
une_autre_exception EXCEPTION;
PRAGMA EXCEPTION_INIT(une_autre_exception, -20011);
BEGIN
DECLARE
vnom client.nom_client%TYPE;
BEGIN
SELECT nom_client INTO vnom FROM CLIENT;
DBMS_OUTPUT.PUT_LINE(’Pas d’’exception levée par la commande SELECT’);
EXCEPTION
WHEN TOO_MANY_ROWS THEN RAISE_APPLICATION_ERROR(-20011, ’Beaucoup trop de lignes ! ’);
END;
EXCEPTION
/*i1*/ WHEN une_autre_exception THEN
DBMS_OUTPUT.PUT_LINE (’Capture avec association du numéro "-20011" à "une_autre_exception"’);
/*i2*/ WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(’Capture de toute exception avec le libellé OTHERS!’);
END;
/

16
(a) Désactivant (en mettant en commentaire) l’instruction i1 de gestion d’exception
(b) Désactivant l’instruction i2 de gestion d’exception
(c) En laissant les 2 en même temps.
(d) En intervertissant leur ordre (mettre i2 avant i1)

Comment comprenez vous tous ces comportements ?

9.6 Procédures et fonctions stockées: blocs nommés


1. Créer une procédure supp commande qui supprime toutes la commandes du client correspon-
dant à l’id passé en paramètre.

(a) Lister la table COMMANDE, exécuter cette procédure sous SQL*Plus sur le client ”c001”
(SQL> EXECUTE ou CALL), puis lister la table COMMANDE pour voir le résultat. Faire un
ROLLBACK pour annuler cette transaction.
(b) Lancer cette procédure dans un simple bloc PL/SQL cette fois ci. Vérifier et annuler la
transaction.

2. Vérifier bien que la procédure créée est bien stockée sous forme d’objet de la base.

3. Créer une procédure en essayant d’affecter une valeur à un paramètre déclarée avec un mode
IN. Que sa passe-t-il ?

4. Créer la fonction factorielle ”factorielle (n)”; Vérifier qu’elle existe bien sous forme d’objets
dans la base.

(a) Exécuter la sous SQL*Plus:


################# SYNTAXE ############
SQL> call factorielle (3) into :x; # x étant déclaré comme variable. Puis SQL> PRINT x
## OU ##
SQL> SELECT factorielle(4) FROM dual;
#####################################

(b) Faire appel à la fonction dans un simple bloc PL/SQL.

5. Avez vous géré précédemment le cas où l’utilisateur donne en paramètre un nombre négatif
à la fonction ”factorielle(n)” ? Gérer le cas où un utilisateur donne un paramètre négatif
en lançant une exception.

(a) Tester la fonction sous SQL*Plus.


(b) Tester la fonction dans un bloc PL/SQL (en captant l’exception si possible).

17
NB sur les PROCEDUREs et FUNCTIONs : ce sont des blocs PL/SQL (nommés) qui ont une partie
DECLARE (implicite), et peuvent aussi avoir une partie EXCEPTION et contenir d’autres blocs.

################# EXEMPLE ############


CREATE OR REPLACE PROCEDURE test IS
BEGIN
DECLARE
test_execp EXCEPTION;
pragma exception_init(test_execp, -20012);
BEGIN
-- instructions
Raise_application_error(-20012, ’un message!’);
EXCEPTION
WHEN test_execp THEN dbms_output.put_line(’un autre message!’);
END;
-- EXCEPTION
-- instructions
END;
/

SQL> execute test;


########################################

9.7 Triggers
################# RAPPEL SUR LES CHA^
INES #####################
SUBSTR(’AZERTY’, 3, 2) retourne ’ER’.
LENGTH(’AZERTY’) renvoie 6
UPPER(’a’) retourne ’A’.
LOWER(’A’) retourne ’a’.

################# SYNTAXE TRIGGER (simplifiée) ################


CREATE OR REPLACE TRIGGER nom_trigger
[BEFORE | AFTER | INSTEAD OF] [INSERT | UPDATE | DELETE] ON
nom_table | nom_vue
[FOR EACH ROW]
[WHEN (condition)]
BEGIN
Corps trigger
END;

################# VALEURS de :OLD et :NEW ####################


Nature de l’événement | :OLD.colonne | :NEW.colonne
-------------------------------------------------------------
INSERT | NULL | Nouvelle valeur.
UPDATE | Ancienne valeur | Nouvelle valeur.
DELETE | Ancienne valeur | NULL

1. Créer les triggers pour effectuer les opérations décrites ci-dessous9 :

(a) Trigger nom client maj: force le nom du client à se mettre en majuscule (avant un
INSERT ou un UPDATE). Insérer un tuple pour vérifier.
9
SQL Developer peut faire une confusion entre variable de session et :old ou :new. Il faut donc faire précéder tout
ordre de création de trigger par l’instruction SET DEFINE OFF. Sous SQL*Plus, il n’y a pas cette confusion

18
(b) Trigger nom client prem maj: force le nom du client à mettre sa première lettre en
majuscule et le reste en minuscule. Insérer un tuple pour vérifier.
i. Ce trigger, programmé pour le même événement que nom client maj, a-t-il eu un
effet sur les insertions ?
ii. Quel ordre semble suivre Oracle pour l’exécution des triggers programmés pour les
mêmes événements ?
iii. Désactiver ou supprimer nom client maj, puis insérer un tuple pour vérifier. Résultat?
(c) Trigger date client: alimente la date de création d’un client par la date du jour
(SYSDATE) avant INSERT. Insérer un tuple pour vérifier.

2. Pour chaque commande de produit, on souhaite connaı̂tre le nom de l’utilisateur Oracle ayant
réalisé la saisie.

(a) La première étape consiste à ajouter une nouvelle colonne à la table COMMANDE: attribut
utilisateur de type VARCHAR2(30). Cette colonne doit accepter la valeur NULL car
pour les lignes de commande existantes, le nom de l’utilisateur10 Oracle est inconnu.
(b) La deuxième étape consiste à créer le trigger approprié.
Faire une insertion pour tester votre trigger.

3. A votre avis, que fait le trigger (a) suivant (faire le test) ? est il correct ? Pourquoi ?

########################### TRIGGER (a) ##########################


create or replace trigger info_user_commande
after insert on commande
for each row
begin
declare
user_de_la_commande commande.utilisateur%type;
begin
select user into user_de_la_commande from dual;
update commande set utilisateur = user_de_la_commande
where id_client = :new.id_client and
id_produit = :new.id_produit;
end;
end;
/
#################################################################

4. Que fait le trigger (b) ? Est il correct ? Pourquoi ? Répond il au besoin de la question 2.?

########################### TRIGGER (b) ##########################


create or replace trigger info_user_commande
after insert on commande
-- for each row
begin
declare
user_de_la_commande commande.utilisateur%type;
begin
10
SELECT user FROM dual; ou SELECT username FROM user users;

19
select user into user_de_la_commande from dual;
update commande set utilisateur = user_de_la_commande;
end;
end;
/
#################################################################

5. Donner à un autre utilisateur (HR ou ETUDIANT) le privilège d’insertion de tuples sur la table
COMMANDE. Dites lui d’insérer des lignes dans la table et faites de même puis regarder le contenu
(penser à valider les transactions).

6. On souhaite connaı̂tre le nombre de commandes fait par un client. Pour éviter d’écrire
une requête qui parcourt à chaque fois la totalité de la table des commandes, une table de
statistiques va être alimentée par un trigger.

(a) Créer la table de statistiques (CREATE TABLE STAT (client VARCHAR2(30), nombre
INTEGER);)
(b) Créer le trigger qui doit s’assurer que le client 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.

NB: Si une requête SELECT ne renvoie rien lors d’une affectation à une variable, une exception
prédéfinie NO DATA FOUND est levée.

Quels inconvénients (deux au moins) trouvez vous à votre trigger ?


7. Comparer le trigger précédent au suivant :

##########################
create or replace trigger alimente_stat
after insert or delete on commande
for each row
declare
nbre_commandes stat.nombre%type;
begin
-- mettre à jour la valeur en fonction du type de requete
if (inserting) then
-- conna^ıtre le nbre actuel pour le client à inserer
select nombre into nbre_commandes from stat where client = :new.id_client;
update stat set nombre = nbre_commandes + 1 where client = :new.id_client;
end if;
if (deleting) then
-- conna^ıtre le nbre actuel pour le client à supprimer
select nombre into nbre_commandes from stat where client = :old.id_client;
update stat set nombre = nbre_commandes - 1 where client = :old.id_client;
end if;
exception
when no_data_found then
if (inserting) then
insert into stat values(:new.id_client, 1);
else null;
end if;
end;

20
/
#########################

8. Créer une vue ”produit laitier” sur la table PRODUIT contenant son id, celui de son four-
nisseur, son libellé et la quantité en stock des produits laitiers.

(a) Lister cette vue.


(b) Lancer ”insert into produit laitier values (’p006’, ’f002’, ’CREME’, 80);”.
(c) Lister à nouveau. Voyez vous la nouvelle donnée insérée ?

Un trigger de type INSTEAD OF (”au lieu de”) 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.

9. Créer alors un trigger INSTEAD OF11 qui, au lieu d’insérer les valeurs voulues dans la vue,
il les insère directement dans la table PRODUIT en mettant la valeur ’Laitier’ dans le champ
type produit. Tester le trigger en faisant insert into produit laitier values(’p007’,
’f002’, ’CREME’, 80);, puis lister la vue.

11
Permet de mettre à jour une vue multitable. Ne s’utilise que sur des vues et ne fait pas intervenir les options
BEFORE et AFTER.

21

Vous aimerez peut-être aussi