5AE7BD0Bd01

8
INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 1/8 - Bertrand LIAUDET INSIA – SIGL 2 Bases de données PL-SQL – ORACLE TP 1 Bertrand LIAUDET Exercice 1 : prise en main du PL-SQL RENDU Chaque exercice impose un rendu. Tous les rendus sont mis dans un fichier texte unique. Ce fichier s’appellera obligatoirement : Nom du fichier : NOM-Prenom-PLSQL-01.txt Ce fichier est envoyé par mail. L’objet du mail est obligatoirement : Objet du mail : NOM-Prenom-PLSQL-01.txt 00-Installation de l’environnement Dans l’environnement déjà créé, ouvrez une session SQL-PLUS en tant que TPSELECT. Vous pouvez utiliser le dossier fournit avec le téléchargement. Rappel : pour créer l’utilisateur TPSELECT : CREATE USER tpselect IDENTIFIED BY "tpselect"; GRANT CONNECT, RESOURCE TO tpselect; 1. Afficher le nom de l’utilisateur est connecté. Show user 2. Afficher les droits de l’utilisateur connecté. select * from user_role_privs; 3. Afficher le catalogue de l’utilisateur connecté. select * from cat; RENDU : le code de réponse aux trois questions. 01-bonjour.sql - Affichage 1. Exécuter le script 01-bonjour.sql dans la calculette slq_plus. Corriger les erreurs. 2. Modifier le script pour que l’affichage se fasse (serveroutput) 3. Modifier le script pour que le temps d’exécution s’affiche (timing)

Transcript of 5AE7BD0Bd01

Page 1: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 1/8 - Bertrand LIAUDET

INSIA – SIGL 2 Bases de données

PL-SQL – ORACLE TP 1

Bertrand LIAUDET

Exercice 1 : prise en main du PL-SQL

RENDU

Chaque exercice impose un rendu. Tous les rendus sont mis dans un fichier texte unique.

Ce fichier s’appellera obligatoirement :

Nom du fichier : NOM-Prenom-PLSQL-01.txt

Ce fichier est envoyé par mail.

L’objet du mail est obligatoirement :

Objet du mail : NOM-Prenom-PLSQL-01.txt

00-Installation de l’environnement

Dans l’environnement déjà créé, ouvrez une session SQL-PLUS en tant que TPSELECT.

Vous pouvez utiliser le dossier fournit avec le téléchargement.

Rappel : pour créer l’utilisateur TPSELECT : CREATE USER tpselect IDENTIFIED BY "tpselect"; GRANT CONNECT, RESOURCE TO tpselect;

1. Afficher le nom de l’utilisateur est connecté. Show user

2. Afficher les droits de l’utilisateur connecté. select * from user_role_privs;

3. Afficher le catalogue de l’utilisateur connecté. select * from cat;

RENDU : le code de réponse aux trois questions.

01-bonjour.sql - Affichage

1. Exécuter le script 01-bonjour.sql dans la calculette slq_plus. Corriger les erreurs.

2. Modifier le script pour que l’affichage se fasse (serveroutput)

3. Modifier le script pour que le temps d’exécution s’affiche (timing)

Page 2: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 2/8 - Bertrand LIAUDET

4. Mettez à jour le fichier login.sql pour que l’affichage se fasse à chaque fois que vous vous connecterez.

RENDU : le fichier login.sql. Explication de la correction apportée. Fichier login.sql

set linesize 120

set pagesize 500

set timing on

set serveroutput on

Fichier corrigé

begin

dbms_output.put_line

('Bonjour '|| user || '. Nous sommes le '

|| to_char(sysdate, 'dd month yyyy') ||

'. Vous êtes bien à l''INSIA !');

end;

/

il y avait deux problèmes d’apostrophe

02-variable.sql – empdept.sql - &

1. Exécutez le script empdept.sql dans la calculette slq_plus.

2. Listez les tables de votre catalogue.

3. Exécutez le script 02-variable.sql

4. Exécutez une deuxième fois le script 02-variable.sql. Que constatez-vous ?

5. Regardez le code et explicitez toute la syntaxe.

RENDU : expliquez la différence entre & et && Le & déclare une variable locale au select

Le && déclare une variable globale à la session. C’ est l’équivalent d’un DEF. Pour voir la valeur de la variable : DEF maVar . Pour annuler la valeur de la variable : UNDEF maVar.

03- moySalDept.sql (empdept) - Fonction

1. Exécutez le script 04-moySalDept.sql dans la calculette slq_plus.

2. affichez le code pris en compte : Col text format A80 Select line, text From user_source where name = ‘MOYSALDEPT’;

3. Explicitez toute la syntaxe.

4. Testez la fonction en utilisant la pseudo-table DUAL

5. Ecrire une requête avec une variable de substitution qui permette d’afficher, pour un département dont on saisira la valeur à l’exécution de la requête, tous les employés qui gagnent plus que la moyenne des salaires du département.

RENDU : les questions 4 et 5

Page 3: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 3/8 - Bertrand LIAUDET

4 :

select moySalDept(10) from dual;

5 :

select * from emp

where deptno=&v_deptno

and sal > moySalDept(deptno);

04- AffEmpDept.sql (empdept) - Procédure

1. Exécutez le script 03-AffEmpDept.sql dans la calculette slq_plus.

2. Affichez les erreurs repérées par le système Show errors;

3. affichez le code pris en compte. Col text format A80 Select line, text From user_source where name = ‘AFFEMPDEPT’;

4. Corrigez la ou les erreurs. Explicitez toute la syntaxe.

5. Appelez la procédures pour toutes les valeurs de département.

6. Mettez à jour la procédure pour qu’elle prenne correctement en compte le cas où le numéro de département n’existe pas.

RENDU : le code de la procédure corrigée avec un appel de cette procédure create or replace

procedure affEmpDept(v_deptno EMP.DEPTNO%TYPE) is

v_nbemp number;

vide number;

Begin

select count(*) into vide from dept where deptno=v _deptno;

if vide=0 then

dbms_output.put_line('Le dept '|| v_deptno || ' n ''existe pas');

return;

end if;

select count(*) into v_nbemp

from emp where deptno=v_deptno;

dbms_output.put_line('Le département '||v_deptno||

' contient '||v_nbemp||' employe(s) : ') ;

dbms_output.put_line('.');

for i_emp in (

select empno, ename, sal, deptno

from emp where deptno = v_deptno

) loop

dbms_output.put_line('. Employé n°'||

i_emp.EMPNO||' : '||i_emp.ENAME||

Page 4: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 4/8 - Bertrand LIAUDET

', salaire = '||i_emp.SAL);

-- il manquait une ' avant ||i_emp.ENAME||

end loop;

dbms_output.put_line('.');

end;

/

call affEmpDept(10);

call affEmpDept(1);

REMARQUE : pour le 5

Soit on fait

call affEmpDept(10);

call affEmpDept(20);

call affEmpDept(30);

call affEmpDept(40);

soit on fait :

create or replace

procedure tousLesAffEmpDept is

Begin

for i_dept in (

select deptno

from dept

) loop

-- dbms_output.put_line('. DEPT n° '|| i_dept .DEPTNO);

affEmpDept(i_dept.DEPTNO) ;

end loop;

end;

/

call tousLesAffEmpDept() ;

A noter que les appels de procédure dans la procédu re se font sans call

05- Curseurs

1. Exécutez les scripts 05-lesEmployes_01.sql et 05-lesEmployes_02.sql dans la calculette slq_plus.

2. Comparez les résultats.

3. Comparez les codes des deux scripts.

4. Transformer les deux scripts en procédure, la procédure prenant le numéro du département en paramètre et l’affichage se limitant aux employés du département traité. Affichez un message spécial si le département est vide.

RENDU : Explication de la différence entre les deux scripts. Code de la procédure de l’exo 4. Le premier code utilise un curseur explicite : curs or ... is select

Le deuxième code utilise un curseur implicite : for .. in

Page 5: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 5/8 - Bertrand LIAUDET

create or replace

procedure affEmpDept(v_deptno EMP.DEPTNO%TYPE) is

v_nbemp number;

i number;

BEGIN

i:=0;

for v_emp in (

select empno, ename, job, sal+nvl(comm, 0) as sal tot

from emp

where deptno=v_deptno

order by saltot desc

)

loop

dbms_output.put_line(v_emp.empno||'-'||v_emp.enam e

||'-'||v_emp.job||'-'||v_emp.saltot);

i:=i+1;

end loop;

if i=0 then

dbms_output.put_line('le département est vide');

end if;

dbms_output.put_line('Nb lignes traitées : '|| i);

END;

/

call affEmpDept(10);

call affEmpDept(1);

06- SQL dynamique - exercice

1. Ecrire une procédure (ou un bloc) qui permet d’afficher, pour chaque table de la BD, le nom de la table, le nombre de tuples, et les 5 premiers tuples de chaque table.

RENDU : Code de la procédure. create or replace

procedure consulteTable is

TYPE NameList IS TABLE OF user_tab_columns.COLUMN_ NAME%TYPE;

i number;

nbColonnes number;

nbTuples number;

v_columname NameList;

v_sqlDynamique varchar2(200);

v_sqlDynamique2 varchar2(1000);

v_sqlDynamique3 varchar2(1000);

v_attribut varchar2(30);

v_valeur varchar2(200);

Begin

i:=0;

Page 6: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 6/8 - Bertrand LIAUDET

-- on boucle sur toutes les tables

for v_table in (select table_name FROM user_tables )

loop

dbms_output.put_line('--------------------------- --------------------------------------------');

-- dbms_output.put_line('Table '||v_table.table_n ame);

-- récupération du nombre de tuples de la table

v_sqlDynamique3:='select count(*) from '|| v_tabl e.table_name;

-- dbms_output.put_line(v_sqlDynamique3);

EXECUTE IMMEDIATE v_sqlDynamique3 into nbTuples;

-- récupération des attributs de la table

v_sqlDynamique:='SELECT COLUMN_NAME FROM user_tab _columns WHERE table_name='''|| v_table.table_name||'''';

-- dbms_output.put_line(v_sqlDynamique);

EXECUTE IMMEDIATE v_sqlDynamique BULK COLLECT INT O v_columname;

-- on peut aussi écrire : notez le 1 et le USING

-- v_sqlDynamique:='SELECT COLUMN_NAME FROM user_ tab_columns WHERE table_name=:1';

-- EXECUTE IMMEDIATE v_sqlDynamique BULK COLLECT INTO v_columname USING v_table.table_name;

-- Création de la requête dans v_sqlDynamique2

v_sqlDynamique2:='BEGIN for v_attributs in (selec t ';

nbColonnes:=0;

FOR j IN 1..v_columname.count LOOP

-- dbms_output.put_line('Attribut : '||v_columna me(j));

v_attribut:=v_columname(j);

v_sqlDynamique2:=v_sqlDynamique2||v_attribut||', ';

nbColonnes:=nbColonnes+1;

END LOOP;

v_sqlDynamique2:=v_sqlDynamique2||' '''' as nb FR OM '||v_table.table_name||' WHERE rownum<6) LOOP

dbms_output.put_line(';

FOR j IN 1..v_columname.count LOOP

v_attribut:=v_columname(j);

v_sqlDynamique2:=v_sqlDynamique2||'v_attributs.' ||v_attribut||'||'' ''|| ';

END LOOP;

v_sqlDynamique2:=v_sqlDynamique2||'v_attributs.nb ); END loop; END;';

-- fin de la création de la requête dans v_sqlDyn amique2

dbms_output.put_line('La Table '||v_table.table_n ame||' possède '|| nbColonnes ||' colonnes et '|| nbTuples ||' tuples : ');

dbms_output.put_line('-');

EXECUTE IMMEDIATE v_sqlDynamique2;

Page 7: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 7/8 - Bertrand LIAUDET

i:=i+1;

dbms_output.put_line('-');

end loop;

-- dbms_output.put_line('Nb lignes traitées : '|| i);

end;

/

call consulteTable();

07- Trigger

1. Exécutez le script 07-trigBefore.txt dans la calculette slq_plus.

2. Affichez le code pris en compte (même principe que pour les procédures et les fonctions) Col text format A80

Select line, text

From user_source

where name = ‘TBU_SAL_EMP’;

3. Affichez les erreurs : trouvez dans les vues publiques la table correspondante et listez son contenu. On pourra se contenter des attributs : name, line, position, text. On fera en sorte que l’affichage soit lisible.

Col text format A80

col name format a15

Select name, line, position, text

from user_errors;

4. Corrigez les erreurs. CREATE OR REPLACE TRIGGER TBU_SAL_EMP

BEFORE UPDATE

OF SAL

ON EMP

FOR EACH ROW

BEGIN

if (:new.sal <= :old.sal ) then

RAISE_APPLICATION_ERROR ( -20000,

'Le nouveau salaire : '||

:new.sal ||

'est inférieur ou égale à l''ancien : ' ||

:old.sal);

end if;

END;

/

// il y a des problèmes de quotes

Page 8: 5AE7BD0Bd01

INSIA - BASES DE DONNÉES – SIGL 2 – PL-SQL-ORACLE-TP 1 - page 8/8 - Bertrand LIAUDET

5. Vérifiez que le trigger fonctionne correctement : augmenter un salaire de 10%. Affichez les salaires.

update emp

set sal = 5500

where empno = 7839;

6. Ouvrez une deuxième session SQL-PLUS pour l’utilisateur TPSELECT. Regardez l’état des salaires. Que constatez-vous ? Regardez l’état des variables d’environnement (SHOW ALL). Comment expliquez-vous la situation ? Dans la première session : validez la transaction. Vérifiez sa prise en compte dans la deuxième session.

Dans la deuxième session, on constate que la modifi cation n’apparaît pas :

Select * from emp where where empno = 7839;

Le SHOW ALL montre le AUTOCOMMIT à OFF

Pour valider la transaction dans la première sessio n :

Commit ;

Dans la 2 ème session : on constate que la modification a été pr ise en compte :

Select * from emp where where empno = 7839;

7. Vérifiez que le trigger fonctionne correctement : essayez de baisser un salaire. update emp

set sal = 4000

where empno = 7839;

update emp

*

ERREUR à la ligne 1 :

ORA-20000: Le nouveau salaire : 4000est inférieur o u égale à l'ancien : 5500

ORA-06512: à "TPSELECT.TBU_SAL_EMP", ligne 3

ORA-04088: erreur lors d'exécution du déclencheur ' TPSELECT.TBU_SAL_EMP'

RENDU : requête du 2, 3. code corrigé du trigger. Solution du 6.