TP-SI-BD II (Oracle)
TP-SI-BD II (Oracle)
TP-SI-BD II (Oracle)
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.
Bien sûr, toutes ces commandes peuvent être réalisées en utilisant tout simplement l’environnement
graphique (explorateur de dossiers).
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.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.
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.
Applications -> Oracle Database 10g Express Edition -> Run SQL Command Line
− 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 :
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.
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
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 ?
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).
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:
6
Πn hom (SON DAGE) ⊆ Πnum h (P ERSON N E)
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:
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.
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 :
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.
(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 ?
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 ?
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 ?
# 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
# 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 / #
##################################################################
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;
/
Il faut remarquer:
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
DECLARE
CURSOR C1 is SELECT * FROM COMMANDE
FOR UPDATE OF QUANTITE;
CMD C1%ROWTYPE;
BEGIN
Open C1;
fetch C1 into CMD;
• 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 ...
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).
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)
(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.
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.
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.
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’.
(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 ?
4. Que fait le trigger (b) ? Est il correct ? Pourquoi ? Répond il au besoin de la question 2.?
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.
##########################
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.
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