TD 4 corrigé

Transcription

TD 4 corrigé
2. Définir le corps du paquetage « pilotes » : définir complètement le curseur « les_pilotes ». Tester
la création du paquetage.
Université Lumière – Lyon 2, Faculté de Sciences Économiques et de Gestion
Master d’Informatique M2 spécialité IUP IDS – Année 2005-2006
Bases de données et programmation – TD n° 4
J. Darmont (http://eric.univ-lyon2.fr/~jdarmont/), 08/11/05
Rappel : Débogage des procédures stockées
3. Ajouter aux spécifications et au corps du paquetage une procédure nommée « afficher » (pas de
paramètre) permettant d’afficher les pilotes à l’écran au format désiré. Utiliser dans le corps de cette
procédure le curseur « les_pilotes » et une variable locale de type « PilNUplet ». Tester la procédure
(EXECUTE pilotes.afficher).
Si une procédure stockée ou une définition de paquetage ou de corps de paquetage n’est pas
correcte, Oracle indique uniquement qu’elle a été créée « avec des erreurs de compilation ». Pour
visualiser ces erreurs, utiliser la commande suivante.
4. Ajouter aux spécifications et au corps du paquetage une procédure nommée « ajouter »
permettant d’ajouter dans la table PILOTE un pilote dont les numéro, nom, prénom, ville et salaire
sont passés en paramètres. Tester la procédure.
SHOW ERRORS
5. Ajouter aux spécifications et au corps du paquetage une procédure nommée « supprimer »
permettant de supprimer de la table PILOTE un pilote dont le numéro est passé en paramètre. Tester
la procédure.
Exercice 1 : Procédure stockée
1. Écrire un bloc PL/SQL anonyme permettant d’afficher les noms des n premiers employés de la
table EMP du TD n° 2 (il est possible de recopier la table DARMONT.EMP si vous n’en disposez
plus). Le nombre n pourra être stocké dans une variable. Gérer le cas où n est plus grand que le
nombre de n-uplets de la table EMP.
2. Transformer le bloc anonyme en procédure stockée nommée « noms_emp », la variable n
devenant un paramètre d’entrée. Tester depuis l’invite de commande SQL*Plus (commandes
EXECUTE noms_emp(3), puis EXECUTE noms_emp(45) par exemple).
6. Ajouter aux spécifications et au corps du paquetage une procédure nommée « modifier »
permettant de modifier dans la table PILOTE un pilote dont les numéro, nom, prénom, ville et
salaire sont passés en paramètres. Tester la procédure.
7. Ajouter aux spécifications et au corps du paquetage une fonction nommée « compter » retournant
un entier et permettant de compter le nombre de n-uplets de la table PILOTE. Tester l’appel de la
fonction à l’aide de la commande EXECUTE de SQL*Plus, puis dans un bloc PL/SQL anonyme.
Exercice 3 : Requête dynamique (altération de schéma paramétrée)
3. Quitter le client SQL*Plus, relancer SQL*Plus et exécuter à nouveau la procédure « noms ».
Conclusion ?
4. Écrire un bloc PL/SQL anonyme incluant la déclaration et l’initialisation de deux variables n1 et
n2 et faisant appel à la procédure « noms_emp » en lui passant successivement ces variables en
paramètre.
1. Dans un bloc PL/SQL anonyme, définir une variable chaîne de caractères nommée « Source » et
lui affecter le nom d’une table de votre compte. Définir une seconde variable chaîne de caractères
nommée « Destination » et lui affecter une valeur quelconque (par exemple, COPIE). Dans le code
du bloc PL/SQL, programmer la copie de la table « Source » dans la table « Destination » (création
de la table « Destination » avec tous les attributs et tous les n-uplets de « Source »). Tester.
Exercice 2 : Paquetage
2. Transformer votre bloc PL/SQL anonyme en procédure stockée prenant en paramètres la table
source et la table destination. Cela fonctionne-t-il ?
On désire mettre en place un paquetage logiciel permettant de gérer la table PILOTE du TD n° 1 (il
est possible de recopier la table DARMONT.PILOTE si vous n’en disposez plus). L’objectif est de
disposer de procédures permettant de :
•
•
•
•
•
afficher le contenu de la table au format Numéro : Prénom NOM (Ville) - Salaire ;
ajouter un pilote ;
supprimer un pilote (connaissant son numéro) ;
modifier un pilote ;
compter les pilotes.
Exercice 4 : Requête dynamique (création de vue paramétrée)
1. Définir les spécifications d’un paquetage nommé « pilotes » contenant :
•
un type enregistrement nommé « PilNUplet » contenant les champs suivants : num, nom,
prenom, vil, et sal. Utiliser exactement le types des champs de la table PILOTE ;
•
un curseur nommé « les_pilotes » retournant un « PilNUplet ».
BD et programmation – TD n° 4
3. Ajouter la mention AUTHID CURRENT_USER dans votre définition de procédure, après la définition
des paramètres (par exemple, CREATE OR REPLACE PROCEDURE copie(source VARCHAR,
destination VARCHAR) AUTHID CURRENT_USER IS). Tester. Qu’est-ce qui a changé ? Pourquoi
cette manipulation était-elle superflue lorsque vous avez créé des procédures stockées dans les
exercices précédents ?
1/3
1. Écrire une procédure stockée prenant en paramètre le nom d’une table et permettant de créer une
vue contenant les noms de tous les attributs de cette table ainsi que leur type. Le nom de la vue
devra être de la forme ATT_nom_de_la_table. Utiliser la vue système USER_TAB_COLUMNS
(TABLE_NAME, COLUMN_NAME, DATA_TYPE…) pour accéder au nom et au type des attributs. Vérifier
le résultat.
BD et programmation – TD n° 4
2/3
NB : Dans les vues systèmes, toutes les chaînes de caractères (comme les noms de tables ou
d’attributs) sont stockées en majuscules.
Correction
-- Ex. 1
Exercice 5 : Curseur simple et requête dynamique (requête paramétrée sur résultat de requête)
CREATE OR REPLACE PROCEDURE noms_emp(n INTEGER) IS
Écrire une procédure stockée permettant de compter le nombre de n-uplets dans toutes les tables de
votre catalogue système (vue système TAB (TNAME, TABTYPE…)). Exclure les vues (type VIEW) de
ce calcul. Afficher le résultat trié par ordre alphabétique sous la forme NOM_TABLE : NB_NUPLETS
n-uplet(s). Gérer le pluriel du mot « n-uplet », qui prend un « s » uniquement quand la taille de la
table est strictement supérieure à 1 n-uplet.
Exercice 6 complémentaire
Écrire une procédure stockée permettant de rechercher les tables contenant un attribut dont le nom
contient une chaîne de caractères passée en paramètres, ainsi que le nom, le type de cet attribut et le
nombre de valeurs distinctes de cet attribut dans la table.
CURSOR employes IS SELECT ename FROM emp;
e employes%ROWTYPE;
BEGIN
OPEN employes;
FETCH employes INTO e;
WHILE employes%FOUND AND employes%ROWCOUNT <= n LOOP
DBMS_OUTPUT.PUT_LINE(e.ename);
FETCH employes INTO e;
END LOOP;
CLOSE employes;
END;
/
-- Bloc anonyme (test)
DECLARE
n1 INTEGER := 3;
n2 INTEGER := 70;
BEGIN
noms_emp(n1);
noms_emp(n2);
END;
/
-- Ex. 2
CREATE OR REPLACE PACKAGE pilotes AS
TYPE PilNUplet IS RECORD(
num pilote.plnum%TYPE,
nom pilote.plnom%TYPE,
prenom pilote.plprenom%TYPE,
vil pilote.ville%TYPE,
sal pilote.salaire%TYPE);
CURSOR les_pilotes RETURN PilNUplet;
PROCEDURE afficher;
PROCEDURE ajouter(num INTEGER, nom VARCHAR, prenom VARCHAR, vil VARCHAR,
sal REAL);
PROCEDURE supprimer(num INTEGER);
PROCEDURE modifier(num INTEGER, nom VARCHAR, prenom VARCHAR, vil VARCHAR,
sal REAL);
FUNCTION compter RETURN INTEGER;
END;
/
BD et programmation – TD n° 4
3/3
BD et programmation – TD n° 4
4/3
CREATE OR REPLACE PACKAGE BODY pilotes AS
-- Ex. 4
CURSOR les_pilotes RETURN PilNUplet IS SELECT * FROM pilote;
CREATE OR REPLACE PROCEDURE VueAtt(tabl VARCHAR) AUTHID CURRENT_USER IS
rq VARCHAR(255);
PROCEDURE afficher IS
t PilNUplet;
BEGIN
FOR t IN les_pilotes LOOP
DBMS_OUTPUT.PUT_LINE(t.num || ' : ' || t.prenom || ' ' || UPPER(t.nom)
|| ' (' || t.vil || ') - ' || t.sal);
END LOOP;
END;
BEGIN
rq := 'CREATE VIEW ATT_' || tabl || ' AS SELECT COLUMN_NAME, DATA_TYPE
FROM USER_TAB_COLUMNS WHERE TABLE_NAME=''' || UPPER(tabl) || '''';
EXECUTE IMMEDIATE rq;
PROCEDURE ajouter(num INTEGER, nom VARCHAR, prenom VARCHAR, vil VARCHAR,
sal REAL) IS
BEGIN
INSERT INTO pilote VALUES(num, nom, prenom, vil, sal);
END;
-- Ex. 5
END;
/
CREATE OR REPLACE PROCEDURE Compte IS
PROCEDURE supprimer(num INTEGER) IS
BEGIN
DELETE FROM pilote WHERE plnum=num;
END;
CURSOR tables IS SELECT TNAME FROM TAB WHERE TABTYPE <> 'VIEW'
ORDER BY TNAME;
t tables%ROWTYPE;
c INTEGER;
fin VARCHAR(9);
PROCEDURE modifier(num INTEGER, nom VARCHAR, prenom VARCHAR, vil VARCHAR,
sal REAL) IS
BEGIN
UPDATE pilote SET plnom=nom, plprenom=prenom, ville=vil, salaire=sal
WHERE plnum=num;
END;
FUNCTION compter RETURN INTEGER IS
n INTEGER;
BEGIN
SELECT COUNT(*) INTO n FROM pilote;
RETURN n;
END;
BEGIN
FOR t IN tables LOOP
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || t.TNAME INTO c;
IF c>1 THEN
fin := ' n-uplets';
ELSE
fin := ' n-uplet';
END IF;
DBMS_OUTPUT.PUT_LINE(t.TNAME || ' : ' || c || fin);
END LOOP;
END;
/
END;
/
-- Ex. 6
-- Test fonction compter
CREATE OR REPLACE PROCEDURE recherche(attribut VARCHAR) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(pilotes.compter);
END;
/
CURSOR liste IS
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM USER_TAB_COLUMNS
WHERE COLUMN_NAME LIKE UPPER('%' || attribut || '%')
ORDER BY TABLE_NAME;
t liste%ROWTYPE;
c INTEGER;
-- Ex. 3
CREATE OR REPLACE PROCEDURE copie(source VARCHAR, destination VARCHAR) AUTHID
CURRENT_USER IS
--DECLARE
-source VARCHAR(20) := 'EMP';
-destination VARCHAR(20) := 'EMP_COPIE';
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || destination || ' AS SELECT * FROM ' ||
source;
END;
/
BD et programmation – TD n° 4
5/3
BEGIN
FOR t IN liste LOOP
EXECUTE IMMEDIATE 'SELECT COUNT(DISTINCT ' || t.COLUMN_NAME || ')
FROM ' || t.TABLE_NAME INTO c;
DBMS_OUTPUT.PUT_LINE(t.TABLE_NAME || ' : ' || t.COLUMN_NAME || ' (' ||
t.DATA_TYPE || ') - ' || c || ' valeurs distinctes');
END LOOP;
END;
/
BD et programmation – TD n° 4
6/3

Documents pareils