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