Académique Documents
Professionnel Documents
Culture Documents
12-1
2.
Une table peut-elle avoir une contrainte unique si elle possde dj une cl
primaire ?
Rponse : Il est possible de spcifier une contrainte unique pour une colonne
de cl non primaire afin de garantir que toutes les valeurs de cette colonne
seront uniques.
3.
Une table qui possde une cl trangre est-elle une table enfant ou une table
parent ?
Rponse : Elle est dfinie dans des tables enfant et assure qu'un
enregistrement parent a t cr avant un enregistrement enfant et que
l'enregistrement enfant sera supprim avant l'enregistrement parent.
4.
5.
6.
Quels sont les types dinstructions qui ne peuvent tre excuts en PL/SQL ?
Rponse : Le langage PL/SQL ne comporte pas d'instructions du Langage de
Dfinition de Donnes ALTER , CREATE , RENAME et
dinstructions de contrle comme GRANT et REVOKE .
7.
8.
9.
12-2
Exercice n 1
Installation
12-3
Quel est l'outil que vous retrouvez sur chaque serveur de base de donnes
installe ?
A. SQL*Plus.
B. iSQL*Plus.
C. SQL*Plus Worksheet
D. Oracle Enterprise Manager.
Rponse :
2.
3.
OUI
Citez trois types de paramtres de mise en forme des rsultats des requtes.
Rponse :
9.
SPOOL
8.
OUI
Quelle est la commande qui vous permet de stocker dans un fichier tout ce qui
est affich lcran ?
Rponse :
7.
CONNECT
6.
Non
5.
Un environnement
Pour utiliser iSQL*Plus sur une machine distante, avez-vous besoin d'installer
le client Oracle ?
Rponse :
4.
Quelle est la commande qui vous permet de dcrire la structure dune vue ?
Rponse :
Exercice n 1
DESC
Installez le schma des exemples pour les ateliers en respectant la dmarche suivante :
C:\>dir Oracle11gSQL_PLSQL.zip
Le volume dans le lecteur C na pas de nom.
Le numro de srie du volume est BC79-154D
Rpertoire de C:\
12-4
20:34
C:\>unzip Oracle11gSQL_PLSQL.zip
Archive: Oracle11gSQL_PLSQL.zip
creating: Oracle11gSQL_PLSQL/
inflating: Oracle11gSQL_PLSQL/DeleteEnvStagiaireXE.sql
inflating: Oracle11gSQL_PLSQL/InitEnvEtoileXE.sql
inflating: Oracle11gSQL_PLSQL/InitEnvStagiaireXE.sql
creating: Oracle11gSQL_PLSQL/stagiaire/
inflating: Oracle11gSQL_PLSQL/stagiaire/CATEGORIES.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/CLIENTS.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/COMMANDES.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/COMMANDES_2009.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/DETAILS_COMMANDES.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/DETAILS_COMMANDES_2009.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/DIM_TEMPS.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/EMPLOYES.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/FOURNISSEURS.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/PRODUITS.DAT
inflating: Oracle11gSQL_PLSQL/stagiaire/STATISTIQUES.DAT
C:\>cd Oracle11gSQL_PLSQL
C:\Oracle11gSQL_PLSQL>dir
Rpertoire de C:\Oracle11gSQL_PLSQL
12/08/2011
12/08/2011
12/08/2011
12/08/2011
12/08/2011
12/08/2011
21:52
21:52
21:52
21:51
20:33
20:33
<REP>
<REP>
<REP>
.
..
550 DeleteEnvStagiaireXE.sql
1 725 InitEnvEtoileXE.sql
30 681 InitEnvStagiaireXE.sql
stagiaire
Exercice n 2
Connexion
12-5
Exercice n 3
Environnement SQL*Plus
NULL ?
-------NOT NULL
NOT NULL
NOT NULL
NOT NULL
Type
------------------NUMBER(6)
CHAR(5)
NUMBER(6)
DATE
DATE
NUMBER(8,2)
Connectez vous ;
SQL> CONNECT STAGIAIRE/PWD
ou
SQL> stagiaire/pwd@//diane.etelia.fr:1521/XE
12-6
Exercice n4
vers
le
fichier
SET PAGESIZE 0
SET ECHO OFF
SET FEEDBACK OFF
SPOOL C:\DESC_ALL.SQL
SELECT 'DESC '||TABLE_NAME FROM CAT
WHERE TABLE_TYPE = 'TABLE' ;
Maintenant vous pouvez arrter la redirection des sorties vers le fichier et excuter
le script ainsi conu.
SQL> SPOOL OFF
SQL> @C:\DESC_ALL.SQL
12-7
2.
sont :
DECLARE ,
3.
PL/SQL
4.
B, C
5.
B, C
6.
A, B
Exercice n1
La prsentation du PL/SQL
Utilisant les proprits dun bloc PL/SQL, vous devez effectuer la srie des oprations
suivantes :
Augmenter les salaires des reprsentants de 10%.
Insrer une novelle catgorie de produits avec le nom et la description suivante :
'Produits cosmtiques'. Faites en sorte que linsertion soit permanente.
Annuler la modification de la table EMPLOYES.
Vrifier que la nouvelle catgorie soit toujours en place.
SQL> SELECT NOM, SALAIRE FROM EMPLOYES
2 WHERE FONCTION LIKE 'Rep%';
NOM
SALAIRE
---------------------------------------- ---------Peacock
2856
...
SQL> UPDATE EMPLOYES SET SALAIRE = SALAIRE * 1.1
2 WHERE FONCTION LIKE 'Rep%';
6 ligne(s) mise(s) jour.
SQL> SELECT NOM, SALAIRE FROM EMPLOYES
2 WHERE FONCTION LIKE 'Rep%';
NOM
SALAIRE
---------------------------------------- ---------Peacock
3141,6
...
12-9
declare
pragma autonomous_transaction;
begin
INSERT INTO CATEGORIES VALUES
( 9,'Produits cosmtiques','Produits cosmtiques');
COMMIT;
end;
/
12-10
NUMBER(8) DEFAULT 10 ;
D. nom_var
BOOLEAN := 1;
E. nom_var
BINARY_INTEGER;
F. 2nom_var
BINARY_INTEGER;
G. a$nom_varG
DATE := '01/01/2006';
H. B#a$nom_var
I.
nom_varI
NUMBER(3):= 123.45678;
J.
nom_var
NUMBER(3) := 1234.5678;
K. nom_varK
Rponse :
2.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
B, C, D, F, J
A. '1 :STAGIAIRE'
B. '2 :STAGIAIRE'
C. '3 :STAGIAIRE'
Rponse :
3.
12-11
Exercice n1
B, D
Crez un bloc PL/SQL dans lequel vous dclarez les variables de la question 24.1-1
les points : A, G, I, K. Affichez les informations stockes dans ces variables.
SQL> set serveroutput on size 5000
SQL> declare
2
nom_varA
NUMBER(8) DEFAULT 10 ;
3
a$nom_varG
DATE := '01/07/2011';
4
nom_varI
NUMBER(3):= 123.45678;
5
nom_varK CONSTANT NUMBER(12,3) := 1234.5678;
6 begin
7
dbms_output.put_line( 'nom_varA
:'||nom_varA );
8
dbms_output.put_line( 'a$nom_varG :'||a$nom_varG);
9
dbms_output.put_line( 'nom_varI
:'||nom_varI );
10
dbms_output.put_line( 'nom_varK
:'||nom_varK );
11 end;
12 /
nom_varA
:10
a$nom_varG :01/07/2011
nom_varI
:123
nom_varK
:1234,568
Procdure PL/SQL termine avec succs.
Dclarez une variable de liaison de type VARCHAR2 . Crez un premier bloc qui
alimente la variable avec la valeur de lutilisateur courant concatne avec la date du
jour. Crez un deuxime bloc qui affiche la variable.
SQL>
SQL>
2
3
4
SQL>
2
3
4
SQL>
12-12
I.
J.
B, E
NUMBER
B. 1024||SYSDATE||USER
Rponse :
VARCHAR2
BOOLEAN
D. 2.5*2.5/0f + 10
Rponse :
BINARY_FLOAT_INFINITY(Infini)
E. INSTR('QUANTITE','T')*256
Rponse :
NUMBER
F. SYSDATE - ROUND(TRUNC(MOD(1600,10),-1),2)
Rponse :
DATE
12-13
BINARY_DOUBLE
H. 2.5f/0||USER
Rponse :
I.
VARCHAR2
Rponse :
Exercice n1
DATE
12-14
declare --F
TYPE var IS VARRAY(3) OF NVARCHAR2(30);
v_1 var:= var('BIZO','FABER');
begin
dbms_output.put_line( v_1(1)||' '||v_1(2));
end;
/
12-15
Sachant que les expressions doivent remplacer les trois points dans le bloc
suivant, quelles sont les expressions invalides ?
declare
v_1 EMPLOYES%ROWTYPE;
TYPE TAB IS TABLE OF EMPLOYES%ROWTYPE
INDEX BY BINARY_INTEGER;
t_1 TAB;
begin
SELECT * INTO v_1 FROM EMPLOYES WHERE NO_EMPLOYE = 5;
end;
/
Rponse :
2.
C, D, E
Sachant que les variables ont t dclares auparavant, quelles sont du bon type
et au bon endroit, quels sont les ordres de mise jour incorrects ?
A. INSERT INTO CATEGORIES VALUES ( 9,'Fruits',
'Fruits') RETURNING ROWID INTO v_rowid;
B. INSERT INTO CATEGORIES VALUES ( 9,'Fruits',
'Fruits') RETURNING * INTO v_cat;
C. UPDATE COMMANDES SET PORT = PORT * 1.05
RETURNING NO_COMMANDE BULK COLLECT INTO v_comm;
D. DELETE CATEGORIES WHERE ROWID = v_1
RETURNING CODE_CATEGORIE INTO v_cat;
E. UPDATE CATEGORIES SET NOM_CATEGORIE = DESCRIPTION
WHERE ROWID = v_1 RETURNING NOM_CATEGORIE
INTO v_cat;
F. UPDATE COMMANDES SET PORT = PORT * 1.05
RETURNING NO_COMMANDE INTO v_comm;
12-16
Exercice n1
B, F, H
12-17
Affichez les deux employs encadrs par 'Buchanan'. Augmentez les frais de
port de '10%' pour toutes les commandes passes par ces deux employs dans
lanne '2011', la modification doit tre faite dans la table INDICATEURS.
Affichez mensuellement pour lanne '2011' les cumuls des frais de port et des
quantits.
SQL> declare
2
TYPE t_employe IS TABLE OF EMPLOYES%ROWTYPE
3
INDEX BY BINARY_INTEGER;
4
TYPE t_emp IS TABLE OF DIM_EMPLOYES.EMPLOYE%TYPE
5
INDEX BY BINARY_INTEGER;
6
TYPE t_mois IS TABLE OF DIM_TEMPS.MOIS%TYPE
7
INDEX BY BINARY_INTEGER;
8
TYPE t_port IS TABLE OF INDICATEURS.PORT%TYPE
9
INDEX BY BINARY_INTEGER;
10
TYPE t_qant IS TABLE OF INDICATEURS.QUANTITE%TYPE
11
INDEX BY BINARY_INTEGER;
12
v_employe t_employe;
13
v_emp
t_emp;
14
v_mois
t_mois;
15
v_sum_port t_port;
16
v_sum_qant t_qant;
17 begin
18
SELECT * BULK COLLECT INTO v_employe FROM EMPLOYES
19
WHERE REND_COMPTE = ( SELECT NO_EMPLOYE
20
FROM EMPLOYES
21
WHERE NOM = 'Buchanan' );
22
dbms_output.put_line( 'Employ : '||v_employe(1).NOM
23
||' '||v_employe(1).NOM);
24
dbms_output.put_line( 'Employ : '||v_employe(2).NOM
12-18
12-19
declare
v_sql_dynamique VARCHAR2(200) :='CREATE TABLE SAV_CAT AS '||'
SELECT * FROM CATEGORIES WHERE 1=2' ;
v_count NUMBER(5);
begin
EXECUTE IMMEDIATE v_sql_dynamique;
SELECT COUNT(*) INTO v_count FROM CATEGORIES;
dbms_output.put_line( 'Enregistrements : '|| v_count);
INSERT INTO SAV_CAT SELECT * FROM CATEGORIES
SELECT COUNT(*) INTO v_count FROM SAV_CAT;
dbms_output.put_line( 'Enregistrements : '|| v_count);
end;
/
A. Enregistrements : 9 9
B. Enregistrements : 9 0
C. Enregistrements : 9
D. Enregistrements :
E. ERREUR la ligne 10 : ...
Rponse : E. L'instruction est cre au moment de l'excution, le compilateur
PL/SQL ne peut pas effectuer la liaison des identifiants (la table SAV_CAT)
dans l'instruction, ce qui nautorise pas la compilation du bloc. Vous pouvez
utiliser le SQL dynamique pour crer une table mais par la suite, dans le bloc,
vous ne pouvez pas utiliser de SQL statique pour manipuler les enregistrements,
il chouerait puisque la table n'existerait que lors de l'excution du bloc.
2.
Exercice n1
Pour des besoins danalyse, on a besoin dune table pour recenser toutes les ventes,
cre chaque jour. La structure de la table est identique celle de la table
VENTES_CLIENTS_2011. Elle doit avoir le nom fourni par lexpression suivante :
12-20
declare
v_nom_table VARCHAR2(32) :='VENTES_'||
TO_CHAR(SYSDATE,'YYYYMMDD');
v_sql_dynamique VARCHAR2(3000) :=
'CREATE TABLE '||v_nom_table||
' AS SELECT * FROM VENTES_CLIENTS_2011 WHERE 1=2' ;
begin
dbms_output.put_line( v_sql_dynamique);
EXECUTE IMMEDIATE v_sql_dynamique;
v_sql_dynamique := 'INSERT INTO '||v_nom_table||
' SELECT EXTRACT( MONTH FROM DATE_COMMANDE) MOIS, '||
'CODE_CLIENT, '
||
'SUM(QUANTITE*PRIX_UNITAIRE) VENTE, '
||
'SUM(QUANTITE*PRIX_UNITAIRE*REMISE) REMISE '
||
'FROM COMMANDES NATURAL JOIN DETAILS_COMMANDES '
||
'WHERE EXTRACT( YEAR FROM DATE_COMMANDE) = 2011 ' ||
'GROUP BY EXTRACT ( MONTH FROM DATE_COMMANDE), '
||
'CODE_CLIENT';
dbms_output.put_line( v_sql_dynamique);
EXECUTE IMMEDIATE v_sql_dynamique;
v_sql_dynamique := 'GRANT SELECT ON STAGIAIRE.'||
v_nom_table||' TO PUBLIC';
dbms_output.put_line( v_sql_dynamique);
EXECUTE IMMEDIATE v_sql_dynamique;
v_sql_dynamique := 'CREATE PUBLIC SYNONYM '||v_nom_table||
' FOR '||v_nom_table;
dbms_output.put_line( v_sql_dynamique);
EXECUTE IMMEDIATE v_sql_dynamique;
end;
/
12-21
I.
J.
Rponse :
2.
D, E, G, H, J
J.
12-22
Exercice n1
B, C, E, J, K, L, N
12-23
Exercice n2
numro
numro
numro
numro
numro
numro
numro
numro
numro
numro
1 est impair
2 est pair
3 est impair
4 est pair
5 est impair
6 est pair
7 est impair
8 est pair
9 est impair
10 est pair
SQL> begin
2
for i in 1..10 loop
3
if mod( i, 2) = 0 then
4
dbms_output.put_line( 'Le numro '||i||' est pair');
5
else
6
dbms_output.put_line( 'Le numro '||i||' est impair');
7
end if;
8
end loop;
9 end;
10 /
Dclarez un tableau de type NUMBER de dix postes, et deux boucles : une qui
affecte le tableau avec les valeurs de 1 9 et une autre qui affiche le tableau partir
du dernier lment affect.
SQL> declare
2
TYPE mon_type_tableau IS TABLE OF NUMBER
3
INDEX BY BINARY_INTEGER;
4
mon_tableau mon_type_tableau;
5 begin
6
for i in 1..9 loop
7
mon_tableau(i) := i;
12-24
loop;
v_compteur in reverse 1..9 loop
dbms_output.put_line( 'L''lment : '||
mon_tableau(v_compteur));
loop;
9
8
7
6
5
4
3
2
1
Augmentez les salaires de '10%' pour tous les employs encadrs par
'Buchanan'. Augmentez la remise accorde par ces employs de '1%'
('REMISE + .01') pour toutes les commandes de lanne '2011'. Effacez
tous les enregistrements de leurs commandes de la table INDICATEURS.
SQL> declare
2
TYPE t_no_emp IS TABLE OF EMPLOYES.NO_EMPLOYE%TYPE
3
INDEX BY BINARY_INTEGER;
4
v_no_emp t_no_emp;
5
nb_enreg SIMPLE_INTEGER := 0;
6 begin
7
UPDATE EMPLOYES
8
SET SALAIRE = SALAIRE * 1.1
9
WHERE REND_COMPTE = ( SELECT NO_EMPLOYE FROM EMPLOYES
10
WHERE NOM = 'Buchanan' ) AND
11
NO_EMPLOYE <> REND_COMPTE
12
RETURNING NO_EMPLOYE BULK COLLECT INTO v_no_emp;
13
nb_enreg := SQL%ROWCOUNT;
14
dbms_output.put_line('Enregistrements modifis : '
15
||SQL%ROWCOUNT);
16
forall i in 1..v_no_emp.count
17
UPDATE DETAILS_COMMANDES SET REMISE = REMISE + 0.01
18
WHERE NO_COMMANDE in (SELECT NO_COMMANDE FROM COMMANDES
19
WHERE NO_EMPLOYE = v_no_emp(i)
20
AND ANNEE
= 2011);
21
dbms_output.put_line('Enregistrements modifis : '
22
||SQL%ROWCOUNT);
23
nb_enreg := nb_enreg + SQL%ROWCOUNT;
24
forall i in 1..v_no_emp.count
25
DELETE INDICATEURS WHERE NO_EMPLOYE = v_no_emp(i);
26
dbms_output.put_line('Enregistrements modifis : '
27
||SQL%ROWCOUNT);
28
nb_enreg := nb_enreg + SQL%ROWCOUNT;
29
if nb_enreg > 0 then
30
COMMIT;
31
end if;
12-25
end;
/
12-26
declare
TYPE t_ref_prod IS TABLE OF PRODUITS.REF_PRODUIT%TYPE
INDEX BY BINARY_INTEGER;
TYPE t_prix
IS TABLE OF PRODUITS.PRIX_UNITAIRE%TYPE
INDEX BY BINARY_INTEGER;
v_ref_prod t_ref_prod;
v_prix
t_prix;
nb_enreg SIMPLE_INTEGER := 0;
begin
UPDATE PRODUITS
SET PRIX_UNITAIRE = PRIX_UNITAIRE * 1.1
WHERE CODE_CATEGORIE = 3
RETURNING REF_PRODUIT, PRIX_UNITAIRE
BULK COLLECT INTO v_ref_prod, v_prix;
dbms_output.put_line('Enregistrements modifis : '
||SQL%ROWCOUNT);
nb_enreg := SQL%ROWCOUNT;
forall i in 1..v_ref_prod.count
UPDATE DETAILS_COMMANDES SET PRIX_UNITAIRE = v_prix(i)
WHERE REF_PRODUIT in v_ref_prod(i)
AND NO_COMMANDE in
( SELECT NO_COMMANDE FROM COMMANDES
WHERE ANNEE = 2011);
dbms_output.put_line('Enregistrements modifis : '
||SQL%ROWCOUNT);
nb_enreg := nb_enreg + SQL%ROWCOUNT;
if nb_enreg > 0 then
null;--COMMIT;
end if;
end;
/
declare
CURSOR c_1 IS SELECT * FROM PRODUITS;
v_1 c_1%ROWTYPE;
begin
/*A*/if c_1%FOUND then
dbms_output.put_line('/*A*/ %FOUND'); end if;
/*B*/if c_1%ISOPEN then
dbms_output.put_line('/*B*/ %ISOPEN'); end if;
/*C*/if c_1%NOTFOUND then
dbms_output.put_line('/*C*/ %NOTFOUND');end if;
/*D*/if c_1%ROWCOUNT >0 then
dbms_output.put_line('/*D*/ %ISOPEN'); end if;
open c_1;
/*E*/if c_1%FOUND then
dbms_output.put_line('/*E*/ %FOUND'); end if;
/*F*/if c_1%ISOPEN then
dbms_output.put_line('/*F*/ %ISOPEN'); end if;
/*G*/if c_1%NOTFOUND then
dbms_output.put_line('/*G*/ %NOTFOUND');end if;
/*H*/if c_1%ROWCOUNT = 0 then
dbms_output.put_line('/*H*/ %ROWCOUNT'); end if;
loop
fetch c_1 into v_1;
exit when c_1%NOTFOUND;
end loop;
/*I*/if c_1%FOUND then
dbms_output.put_line('/*I*/ %FOUND'); end if;
/*J*/if c_1%ISOPEN then
dbms_output.put_line('/*J*/ %ISOPEN'); end if;
/*K*/if c_1%NOTFOUND then
dbms_output.put_line('/*K*/ %NOTFOUND');end if;
/*L*/if c_1%ROWCOUNT >0 then
dbms_output.put_line('/*L*/ %ROWCOUNT'); end if;
close c_1;
/*M*/if c_1%FOUND then
dbms_output.put_line('/*M*/ %FOUND'); end if;
/*N*/if c_1%ISOPEN then
dbms_output.put_line('/*N*/ %ISOPEN'); end if;
/*O*/if c_1%NOTFOUND then
dbms_output.put_line('/*O*/ %NOTFOUND');end if;
/*P*/if c_1%ROWCOUNT >0 then
dbms_output.put_line('/*P*/ %ISOPEN'); end if;
end;
/
12-27
Quelles sont les instructions qui gnrent une erreur due une lecture des
attributs du curseur ?
Rponse :
2.
A, C, D, M, O, P
Si on efface les instructions qui gnrent une erreur, quelles sont les autres
instructions qui valident la condition et affichent la chaine avec leur lettre et
leur attribut ?
Rponse :
Exercice n1
F, H, J, K, L
declare
CURSOR c_quantite_clients IS
SELECT EXTRACT ( YEAR FROM DATE_COMMANDE) ANNEE,
EXTRACT ( MONTH FROM DATE_COMMANDE) MOIS,
CODE_CLIENT,
SUM(QUANTITE) QUANTITE,
SUM(PORT) PORT
FROM
COMMANDES NATURAL JOIN DETAILS_COMMANDES
GROUP BY EXTRACT ( YEAR FROM DATE_COMMANDE),
EXTRACT ( MONTH FROM DATE_COMMANDE),
CODE_CLIENT;
v_quantite_clients c_quantite_clients%ROWTYPE;
begin
delete QUANTITES_CLIENTS;
open c_quantite_clients;
if c_quantite_clients%ISOPEN then
loop
fetch c_quantite_clients into v_quantite_clients;
exit when c_quantite_clients%NOTFOUND;
INSERT INTO QUANTITES_CLIENTS VALUES v_quantite_clients;
end loop;
end if;
close c_quantite_clients;
COMMIT;
end;
/
12-28
FROM
COMMANDES NATURAL JOIN DETAILS_COMMANDES
WHERE EXTRACT ( YEAR FROM DATE_COMMANDE) = a_annee
GROUP BY EXTRACT ( YEAR FROM DATE_COMMANDE),
EXTRACT ( MONTH FROM DATE_COMMANDE);
v_ventes_mois c_ventes_mois%ROWTYPE;
v_annee NUMBER(4) := &anne_du_calcul;
begin
delete VENTES_MOIS WHERE ANNEE = v_annee;
open c_ventes_mois(v_annee);
if c_ventes_mois%ISOPEN then
loop
fetch c_ventes_mois into v_ventes_mois;
exit when c_ventes_mois%NOTFOUND;
INSERT INTO VENTES_MOIS VALUES v_ventes_mois;
end loop;
end if;
close c_ventes_mois;
COMMIT;
end;
/
declare
CURSOR c_emp IS SELECT EMPLOYE,FONCTION FROM DIM_EMPLOYES;
TYPE t_emp IS TABLE OF c_emp%ROWTYPE;
v_emp t_emp;
begin
open c_emp;
fetch c_emp bulk collect into v_emp;
for i in 1..v_emp.count
loop
dbms_output.put_line( 'Employ : '||v_emp(i).EMPLOYE||
' -- Fonction :'||v_emp(i).FONCTION);
end loop;
close c_emp;
end;
/
12-29
declare
v_annee NUMBER(4) := &anne_du_calcul;
begin
DELETE VENTES_CLIENTS WHERE ANNEE = v_annee;
for i in ( SELECT EXTRACT ( YEAR FROM DATE_COMMANDE) ANNEE,
EXTRACT ( MONTH FROM DATE_COMMANDE) MOIS,
CODE_CLIENT,
SUM(QUANTITE*PRIX_UNITAIRE) VENTE,
SUM(QUANTITE*PRIX_UNITAIRE*REMISE) REMISE
FROM
COMMANDES NATURAL JOIN DETAILS_COMMANDES
WHERE EXTRACT( YEAR FROM DATE_COMMANDE) = v_annee
GROUP BY EXTRACT( YEAR FROM DATE_COMMANDE),
EXTRACT( MONTH FROM DATE_COMMANDE),
CODE_CLIENT)
loop
INSERT INTO VENTES_CLIENTS VALUES i;
end loop;
COMMIT;
end;
/
12-30
Exercice n2
Crez le bloc PL/SQL qui permet de mettre les frais de port zro pour toutes les
commandes de clients qui habitent dans la mme ville que les fournisseurs des
produits achets pour uniquement lanne passe en argument au curseur. Les
modifications sont effectues dans la table COMMANDES du modle relationnel mais
en mme temps vous devez effacer les enregistrements de ces commandes dans la
table INDICATEURS du modle toile.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
declare
CURSOR c_commandes (a_annee NUMBER)
IS
SELECT B.NO_COMMANDE, B.PORT
FROM CLIENTS A,
COMMANDES B,
DETAILS_COMMANDES C,
PRODUITS D, FOURNISSEURS E
WHERE EXTRACT(YEAR FROM B.DATE_COMMANDE) = a_annee AND
A.VILLE
= E.VILLE
AND
A.CODE_CLIENT
= B.CODE_CLIENT
AND
B.NO_COMMANDE
= C.NO_COMMANDE
AND
C.REF_PRODUIT
= D.REF_PRODUIT
AND
D.NO_FOURNISSEUR = E.NO_FOURNISSEUR
FOR UPDATE OF B.PORT;
v_annee NUMBER(4) := &anne_du_calcul;
begin
for v_commandes in c_commandes(v_annee)
loop
UPDATE COMMANDES SET PORT = 0 WHERE CURRENT OF c_commandes;
DELETE INDICATEURS
WHERE NO_COMMANDE = v_commandes.NO_COMMANDE;
dbms_output.put_line( 'Numro de commande effac :'||
v_commandes.NO_COMMANDE);
end loop;
COMMIT;
end;
/
Exercice n3
Crez le bloc PL/SQL qui permet dafficher partir du modle toile lune des tables :
VENTES_CLIENTS_2009,
Tsoft/Eyrolles PL/SQL pour Oracle 12c
12-31
12-32
declare
TYPE curs_aff IS REF CURSOR;
c_aff
curs_aff;
v_aff
VENTES_CLIENTS%ROWTYPE;
v_annee
NUMBER(4)
:= &annee_du_calcul;
v_SQL_SELECT varchar2(2000)
:=' MOIS,CODE_CLIENT,VENTE,REMISE FROM ';
v_table
varchar2(2000);
begin
for i in ( SELECT TABLE_NAME FROM USER_TABLES
WHERE TABLE_NAME = 'VENTES_CLIENTS_'||v_annee)
loop
v_table := i.TABLE_NAME;
end loop;
if length(v_table) > 0 then
v_SQL_SELECT := ' SELECT '||v_annee||' ANNEE,'||
v_SQL_SELECT||v_table;
else
v_SQL_SELECT := ' SELECT ANNEE,'||v_SQL_SELECT||
'VENTES_CLIENTS';
end if;
open c_aff FOR v_SQL_SELECT;
loop
fetch c_aff into v_aff;
exit when c_aff%NOTFOUND;
dbms_output.put_line( v_aff.ANNEE||' '||v_aff.MOIS||' '||
v_aff.CODE_CLIENT||' '||v_aff.VENTE||' '||v_aff.REMISE);
end loop;
close c_aff;
end;
/
declare
EXCEPTION_1 EXCEPTION;
EXCEPTION_2 EXCEPTION;
EXCEPTION_3 EXCEPTION;
EXCEPTION_4 EXCEPTION;
EXCEPTION_5 EXCEPTION;
begin --bloc 1
begin --bloc 2
begin --bloc 3
begin --bloc 4
begin --bloc 5
RAISE EXCEPTION_5;
dbms_output.put_line( 'Suite traitements bloc 5.');
exception--exception bloc 5
when EXCEPTION_5 then
dbms_output.put_line( 'Exception EXCEPTION_5');
RAISE EXCEPTION_4;
end;--end bloc 5
dbms_output.put_line( 'Suite traitements bloc 4.');
exception--exception bloc 4
when EXCEPTION_4 then
dbms_output.put_line( 'Exception EXCEPTION_4');
RAISE EXCEPTION_3;
end;--end bloc 4
dbms_output.put_line( 'Suite traitements bloc 3.');
exception--exception bloc 3
when EXCEPTION_3 then
dbms_output.put_line( 'Exception EXCEPTION_3');
RAISE EXCEPTION_2;
end;--end bloc 3
dbms_output.put_line( 'Suite traitements bloc 2.');
exception--exception bloc 2
when EXCEPTION_2 then
dbms_output.put_line( 'Exception EXCEPTION_2');
RAISE EXCEPTION_1;
end;--end bloc 2
dbms_output.put_line( 'Suite traitements bloc 1.');
exception--exception bloc 1
when EXCEPTION_1 then
dbms_output.put_line( 'Exception EXCEPTION_1');
when OTHERS then
dbms_output.put_line( 'Une autre erreur.');
end;--end bloc 1
/
1.
12-33
4.
3.
2.
1.
B.
Exception EXCEPTION_5
Suite traitements bloc
Suite traitements bloc
Suite traitements bloc
Suite traitements bloc
4.
3.
2.
1.
C.
Exception
Exception
Exception
Exception
Exception
EXCEPTION_5
EXCEPTION_4
EXCEPTION_3
EXCEPTION_2
EXCEPTION_1
D.
Suite
Suite
Suite
Suite
Suite
traitements
traitements
traitements
traitements
traitements
bloc
bloc
bloc
bloc
bloc
5.
4.
3.
2.
1.
E.
Une autre erreur.
Rponse :
Exercice n1
12-34
12-35
12-36
Exercice n2
declare
DELETE_CASCADE_ENFANT EXCEPTION;
PRAGMA EXCEPTION_INIT(DELETE_CASCADE_ENFANT, -2292);
v_no_commande COMMANDES.NO_COMMANDE%TYPE := &no_commande;
begin
DELETE COMMANDES WHERE NO_COMMANDE = v_no_commande;
exception
when DELETE_CASCADE_ENFANT then
dbms_output.put_line( 'Exception : DELETE_CASCADE_ENFANT ');
DELETE DETAILS_COMMANDES WHERE NO_COMMANDE = v_no_commande;
DELETE COMMANDES WHERE NO_COMMANDE = v_no_commande;
end;
/
Exercice n2
12-37
Permettre de saisir les informations dun employ et de les insrer dans la table
EMPLOYES. Si lge de lemploy est infrieur 18 ans, ninsrez pas et lancez
une exception.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
12-38
declare
UPDATE_EMPLOYES EXCEPTION;
v_employe EMPLOYES%ROWTYPE;
begin
v_employe.NO_EMPLOYE
:= &NO_EMPLOYE;
v_employe.REND_COMPTE
:= &REND_COMPTE;
v_employe.NOM
:= '&NOM';
v_employe.PRENOM
:= '&PRENOM';
v_employe.FONCTION
:= '&FONCTION';
v_employe.TITRE
:= '&TITRE';
v_employe.DATE_NAISSANCE := '&DATE_NAISSANCE';
v_employe.DATE_EMBAUCHE := '&DATE_EMBAUCHE';
v_employe.SALAIRE
:= &SALAIRE;
v_employe.COMMISSION
:= &COMMISSION;
if (SYSDATE - v_employe.DATE_NAISSANCE)/365 < 18 then
RAISE UPDATE_EMPLOYES;
end if;
INSERT INTO EMPLOYES VALUES v_employe;
exception
when UPDATE_EMPLOYES then
dbms_output.put_line(
'Exception utilisateur : UPDATE_EMPLOYES ');
end;
/
declare
PROCEDURE ProcedureA IS
begin
dbms_output.put_line( 'ProcedureA');
ProcedureB;
end;
PROCEDURE ProcedureB IS
begin
dbms_output.put_line( 'ProcedureB');
end;
begin
ProcedureA;
end;
/
1.
2.
SQL>
2
3
4
5
6
A, D
3.
Quelles sont les syntaxes qui affichent la chane suivante '1 2 0' ?
A. exec p1;
B. exec p1(1,2,3);
C. exec p1(1,2);
D. exec p1(3);
12-39
J.
Rponse :
Exercice n1
C, G, J
Les fonctions
ou
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
12-40
AS
begin
for v_code_categorie in ( SELECT NO_FOURNISSEUR
FROM FOURNISSEURS WHERE NO_FOURNISSEUR = a_no)
loop
RETURN TRUE;--Fournisseur trouv
end loop;
RETURN FALSE;--Fournisseur non trouv
end;
/
12-41
v_num
NUMBER;
v_cle
USER_CONS_COLUMNS.COLUMN_NAME%TYPE;
v_type
USER_TAB_COLUMNS.DATA_TYPE%TYPE;
begin
SELECT COLUMN_NAME, DATA_TYPE INTO v_cle, v_type
FROM USER_CONSTRAINTS NATURAL JOIN USER_CONS_COLUMNS
JOIN USER_TAB_COLUMNS USING( TABLE_NAME, COLUMN_NAME )
WHERE CONSTRAINT_TYPE = 'P'AND
TABLE_NAME = UPPER( a_table);
v_requete := v_requete||a_table||' WHERE '||v_cle;
case v_type
when 'NUMBER' then
v_requete := v_requete||' = '||a_valeur;
when 'DATE' then
if not REGEXP_LIKE( a_valeur,
'[[:digit:]]{2}\/[[:digit:]]{2}\/[[:digit:]]{4}') then
dbms_output.put_line('Ce n''est pas un format de '||
'date valide. Le format est : ''DD/MM/YYYY''');
RETURN FALSE;
end if;
v_requete := v_requete||' = TO_DATE('||''''||
a_valeur||''', ''DD/MM/YYYY'')';
else
v_requete := v_requete||' LIKE '||''''||a_valeur||'''';
end case;
EXECUTE IMMEDIATE v_requete INTO v_num;
if v_num = 1 then
RETURN TRUE;
else
RETURN FALSE;
end if;
exception
when NO_DATA_FOUND then
dbms_output.put_line('La table n''a pas de cl '||
'primaire ou elle n''existe pas.');
RETURN FALSE;
when TOO_MANY_ROWS then
dbms_output.put_line(
'La table a une cl primaire multiple');
RETURN FALSE;
end VerifieEnregDansLaTable;
/
SQL> begin
2
if VerifieEnregDansLaTable('&nom_table','&la_cle')
3
then
4
dbms_output.put_line('Enregistrement trouv');
5
else
6
dbms_output.put_line('Enregistrement non trouv');
7
end if;
8 end;
9 /
12-42
Exercice n2
Les procdures
12-43
Saisir toutes les informations ncessaires pour insrer un produit dans la table
PRODUITS. Utilisez la fonction de contrle dexistence dun enregistrement
prcdemment cre pour vrifier toutes les contraintes de cl primaire ncessaires.
Crez trois procdures, la premire qui a comme argument un enregistrement du
mme type que la table produits, la deuxime avec une liste arguments
reprsentants les champs de la table produits et la troisime qui effectue le
traitement. Les deux premires procdures doivent avoir le mme nom, le
traitement est effectu par la troisime. La premire et la deuxime procdures
appellent la troisime. Ainsi la premire et la deuxime procdure ne sont quun
moyen de diversifier les possibilits daccs la troisime procdure.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
12-44
SQL>
2
3
4
5
6
7
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
12-45
12-46
BEGIN
---------------------La table DIM_CLIENTS---------------------MERGE INTO DIM_CLIENTS CIBLE
USING ( SELECT CODE_CLIENT,SOCIETE,VILLE,PAYS
FROM CLIENTS ) SOURCE
ON ( CIBLE.CODE_CLIENT = SOURCE.CODE_CLIENT)
WHEN MATCHED THEN
UPDATE SET CIBLE.CLIENT = SOURCE.SOCIETE,
CIBLE.VILLE = SOURCE.VILLE,
CIBLE.PAYS
= SOURCE.PAYS
WHEN NOT MATCHED THEN
INSERT ( CODE_CLIENT,CLIENT,VILLE,PAYS)
VALUES ( SOURCE.CODE_CLIENT,SOURCE.SOCIETE,
SOURCE.VILLE,SOURCE.PAYS);
dbms_output.put_line('Table DIM_CLIENTS '||
'enregistrements modifies : '||SQL%ROWCOUNT);
---------------------La table DIM_EMPLOYES--------------------MERGE INTO DIM_EMPLOYES CIBLE
USING ( SELECT NO_EMPLOYE,NOM||' '||PRENOM EMPLOYE,
FONCTION
FROM EMPLOYES ) SOURCE
ON ( CIBLE.NO_EMPLOYE = SOURCE.NO_EMPLOYE)
WHEN MATCHED THEN
UPDATE SET CIBLE.EMPLOYE = SOURCE.EMPLOYE,
CIBLE.FONCTION = SOURCE.FONCTION
WHEN NOT MATCHED THEN
INSERT ( NO_EMPLOYE,EMPLOYE,FONCTION)
VALUES ( SOURCE.NO_EMPLOYE,SOURCE.EMPLOYE,
SOURCE.FONCTION);
dbms_output.put_line('Table DIM_EMPLOYES '||
'enregistrements modifies : '||SQL%ROWCOUNT);
---------------------La table DIM_PRODUITS--------------------MERGE INTO DIM_PRODUITS CIBLE
USING ( SELECT REF_PRODUIT,NOM_PRODUIT,NOM_CATEGORIE
FROM PRODUITS NATURAL JOIN CATEGORIES ) SOURCE
ON ( CIBLE.REF_PRODUIT = SOURCE.REF_PRODUIT)
WHEN MATCHED THEN
UPDATE SET CIBLE.NOM_PRODUIT
= SOURCE.NOM_PRODUIT,
CIBLE.NOM_CATEGORIE = SOURCE.NOM_CATEGORIE
WHEN NOT MATCHED THEN
INSERT ( REF_PRODUIT,NOM_PRODUIT,NOM_CATEGORIE )
VALUES ( SOURCE.REF_PRODUIT,SOURCE.NOM_PRODUIT,
SOURCE.NOM_CATEGORIE);
dbms_output.put_line('Table DIM_PRODUITS '||
'enregistrements modifies : '||SQL%ROWCOUNT);
---------------------La table INDICATEURS---------------------MERGE INTO INDICATEURS CIBLE
USING ( SELECT DATE_COMMANDE, REF_PRODUIT, CODE_CLIENT,
NO_EMPLOYE, NO_COMMANDE, PORT,
QUANTITE, PRIX_UNITAIRE
FROM EMPLOYES JOIN COMMANDES USING ( NO_EMPLOYE)
JOIN DETAILS_COMMANDES
USING ( NO_COMMANDE ) ) SOURCE
ON ( CIBLE.JOUR
= SOURCE.DATE_COMMANDE AND
CIBLE.REF_PRODUIT = SOURCE.REF_PRODUIT
AND
CIBLE.CODE_CLIENT = SOURCE.CODE_CLIENT
AND
CIBLE.NO_EMPLOYE = SOURCE.NO_EMPLOYE
AND
CIBLE.NO_COMMANDE = SOURCE.NO_COMMANDE )
WHEN MATCHED THEN
UPDATE SET CIBLE.PORT = SOURCE.PORT,
CIBLE.QUANTITE = SOURCE.QUANTITE,
CIBLE.PRIX_UNITAIRE = SOURCE.PRIX_UNITAIRE
WHEN NOT MATCHED THEN
INSERT ( JOUR,REF_PRODUIT,CODE_CLIENT,NO_EMPLOYE,
NO_COMMANDE,PORT,QUANTITE,PRIX_UNITAIRE )
VALUES ( SOURCE.DATE_COMMANDE,SOURCE.REF_PRODUIT,
SOURCE.CODE_CLIENT,SOURCE.NO_EMPLOYE,
SOURCE.NO_COMMANDE,SOURCE.PORT,
SOURCE.QUANTITE,SOURCE.PRIX_UNITAIRE);
dbms_output.put_line('Table INDICATEURS '||
'enregistrements modifies : '||SQL%ROWCOUNT);
COMMIT;
END MAJ_MODEL_ETOILE;
/
Effacez dabord les enregistrements, puis insrez les dans les sept tables du
modle toile :
QUANTITES_CLIENTS,
VENTES_CLIENTS,
VENTES_ANNEES,
VENTES_MOIS
VENTES_CLIENTS_2009
VENTES_CLIENTS_2010
VENTES_CLIENTS_2011
SQL> CREATE OR REPLACE PROCEDURE MAJ_TABLES_AGREGATS
2 AS
3 BEGIN
4
DELETE QUANTITES_CLIENTS;
5
DELETE VENTES_CLIENTS;
6
DELETE VENTES_ANNEES;
7
DELETE VENTES_MOIS;
8
DELETE VENTES_CLIENTS_2009;
9
DELETE VENTES_CLIENTS_2010;
10
DELETE VENTES_CLIENTS_2011;
11
INSERT ALL
12
WHEN G = 0 THEN
13
INTO VENTES_CLIENTS
14
VALUES ( ANNEE, MOIS, CODE_CLIENT, VENTE, REMISE)
15
INTO QUANTITES_CLIENTS
16
VALUES ( ANNEE, MOIS, CODE_CLIENT, QUANTITE, PORT)
17
WHEN G = 3 THEN
18
INTO VENTES_ANNEES
19
VALUES ( ANNEE, VENTE, REMISE)
12-47
WHEN G = 1 THEN
INTO VENTES_MOIS
VALUES ( ANNEE, MOIS, VENTE, REMISE)
WHEN ANNEE = 1996 THEN
INTO VENTES_CLIENTS_2009
VALUES ( MOIS, CODE_CLIENT, VENTE, REMISE)
WHEN ANNEE = 1997 THEN
INTO VENTES_CLIENTS_2010
VALUES ( MOIS, CODE_CLIENT, VENTE, REMISE)
WHEN ANNEE = 1998 THEN
INTO VENTES_CLIENTS_2011
VALUES ( MOIS, CODE_CLIENT, VENTE, REMISE)
SELECT GROUPING_ID( EXTRACT ( YEAR FROM DATE_COMMANDE),
EXTRACT ( MONTH FROM DATE_COMMANDE),
CODE_CLIENT ) G,
EXTRACT ( YEAR FROM DATE_COMMANDE) ANNEE,
EXTRACT ( MONTH FROM DATE_COMMANDE) MOIS,
CODE_CLIENT,
SUM(QUANTITE*PRIX_UNITAIRE) VENTE,
SUM(QUANTITE*PRIX_UNITAIRE*REMISE) REMISE,
SUM(QUANTITE) QUANTITE,
SUM(PORT) PORT
FROM
COMMANDES NATURAL JOIN DETAILS_COMMANDES
GROUP BY ROLLUP
(EXTRACT ( YEAR FROM DATE_COMMANDE),
EXTRACT ( MONTH FROM DATE_COMMANDE),
CODE_CLIENT);
dbms_output.put_line('Enregistrements insrs : '
||SQL%ROWCOUNT);
COMMIT;
END MAJ_TABLES_AGREGATS;
/
12-48
1.
2.
Exercice n1
Les packages
12-49
Une procdure dinsertion dun employ dans la table EMPLOYES. Il faut contrler
que le suprieur hirarchique existe dj dans la table. Lge de lemploy doit tre
suprieur 18 ans. Vous pouvez utiliser une constante pour stocker lge
minimum. Il faut galement contrler si lemploy nexiste pas dj dans la table.
PROCEDURE AddEmploye
( a_no_emloye
EMPLOYES.NO_EMPLOYE%TYPE,
a_rend_compte
EMPLOYES.REND_COMPTE%TYPE,
a_nom
EMPLOYES.NOM%TYPE,
a_prenom
EMPLOYES.PRENOM%TYPE,
a_fonction
EMPLOYES.FONCTION%TYPE,
a_titre
EMPLOYES.TITRE%TYPE,
a_date_naissance EMPLOYES.DATE_NAISSANCE%TYPE,
a_date_embauche EMPLOYES.DATE_EMBAUCHE%TYPE,
a_salaire
EMPLOYES.SALAIRE%TYPE,
a_commission
EMPLOYES.COMMISSION%TYPE )
IS
BEGIN
if sysdate - a_date_naissance < v_age_minim then
raise e_Age;
end if;
if ControleEmploye( a_no_emloye) then
raise e_Employe;
end if;
if not ControleEmploye( a_rend_compte) then
raise e_Superieur;
end if;
12-50
Pour les tests du package, crez un script SQL qui vous permette de saisir les
informations pour lajout dun employ, laugmentation et la suppression.
-- cration des valeurs saisir
accept vs_no_emloye
prompt "N employ
accept vs_rend_compte
prompt "Rend compte
accept vs_nom
prompt "Nom
accept vs_prenom
prompt "Prnom
accept vs_fonction
prompt "Fonction
accept vs_titre
prompt "Titre
accept vs_date_naissance prompt "Date de naissance
accept vs_date_embauche prompt "Date embauche
accept vs_salaire
prompt "Salaire
accept vs_commission
prompt "Commission
:
:
:
:
:
:
:
:
:
:
"
"
"
"
"
"
"
"
"
"
BEGIN
GererEmploye.AddEmploye
( &vs_no_emloye,&vs_rend_compte,'&vs_nom',
'&vs_prenom','&vs_fonction','&vs_titre',
'&vs_date_naissance','&vs_date_embauche',
&vs_salaire,&vs_commission);
EXCEPTION
when GererEmploye.e_Salaire then
dbms_output.put_line( 'Le salaire n''est pas valide.');
when GererEmploye.e_Superieur then
dbms_output.put_line( 'Le suprieur n''est pas valide.');
when GererEmploye.e_Employe then
dbms_output.put_line( 'L''employ n''est pas valide.');
when GererEmploye.e_Age then
dbms_output.put_line( 'L''age nest pas valide.');
when OTHERS then
dbms_output.put_line( 'Erreur.');
END;
Rponse :
12-51
v_employe
EMPLOYES%ROWTYPE;
FUNCTION ControleEmploye
( a_no_emloye EMPLOYES.NO_EMPLOYE%TYPE)
RETURN BOOLEAN;
PROCEDURE AddEmploye
( a_no_emloye
EMPLOYES.NO_EMPLOYE%TYPE,
a_rend_compte
EMPLOYES.REND_COMPTE%TYPE,
a_nom
EMPLOYES.NOM%TYPE,
a_prenom
EMPLOYES.PRENOM%TYPE,
a_fonction
EMPLOYES.FONCTION%TYPE,
a_titre
EMPLOYES.TITRE%TYPE,
a_date_naissance EMPLOYES.DATE_NAISSANCE%TYPE,
a_date_embauche EMPLOYES.DATE_EMBAUCHE%TYPE,
a_salaire
EMPLOYES.SALAIRE%TYPE,
a_commission
EMPLOYES.COMMISSION%TYPE );
PROCEDURE Supprimer
( a_no_emloye
EMPLOYES.NO_EMPLOYE%TYPE);
PROCEDURE Augmenter
( a_no_emloye
EMPLOYES.NO_EMPLOYE%TYPE,
a_salaire
EMPLOYES.SALAIRE%TYPE :=0 );
END GererEmploye;
/
Package cr.
SQL> CREATE OR REPLACE PACKAGE BODY GererEmploye
2 IS
3
v_age_minim
CONSTANT NUMBER(2):= 18;
4
v_sum_salaire
EMPLOYES.SALAIRE%TYPE;
5
v_avg_salaire
EMPLOYES.SALAIRE%TYPE;
6
--------------- FUNCTION ControleEmploye -------------------7
FUNCTION ControleEmploye
8
( a_no_emloye EMPLOYES.NO_EMPLOYE%TYPE)
9
RETURN BOOLEAN
10
AS
11
BEGIN
12
for v_employe in ( SELECT NO_EMPLOYE FROM EMPLOYES
13
WHERE NO_EMPLOYE = a_no_emloye) loop
14
RETURN TRUE;
15
end loop;
16
RETURN FALSE;
17
END ControleEmploye;
18
--------------- PROCEDURE AddEmploye ---------------------19
PROCEDURE AddEmploye
20
( a_no_emloye
EMPLOYES.NO_EMPLOYE%TYPE,
21
a_rend_compte
EMPLOYES.REND_COMPTE%TYPE,
22
a_nom
EMPLOYES.NOM%TYPE,
23
a_prenom
EMPLOYES.PRENOM%TYPE,
24
a_fonction
EMPLOYES.FONCTION%TYPE,
25
a_titre
EMPLOYES.TITRE%TYPE,
26
a_date_naissance EMPLOYES.DATE_NAISSANCE%TYPE,
27
a_date_embauche EMPLOYES.DATE_EMBAUCHE%TYPE,
28
a_salaire
EMPLOYES.SALAIRE%TYPE,
29
a_commission
EMPLOYES.COMMISSION%TYPE )
12-52
IS
BEGIN
if sysdate - a_date_naissance < v_age_minim then
raise e_Age;
end if;
if ControleEmploye( a_no_emloye) then
raise e_Employe;
end if;
if not ControleEmploye( a_rend_compte) then
raise e_Superieur;
end if;
if a_date_embauche > sysdate then
raise e_Embauche;
end if;
INSERT INTO EMPLOYES ( NO_EMPLOYE, REND_COMPTE, NOM,
PRENOM, FONCTION, TITRE,
DATE_NAISSANCE, DATE_EMBAUCHE,
SALAIRE, COMMISSION )
VALUES
( a_no_emloye, a_rend_compte, a_nom,
a_prenom, a_fonction, a_titre,
a_date_naissance, a_date_embauche,
a_salaire, a_commission);
END AddEmploye;
--------------- PROCEDURE Supprimer ---------------------PROCEDURE Supprimer
( a_no_emloye EMPLOYES.NO_EMPLOYE%TYPE)
IS
BEGIN
DELETE EMPLOYES WHERE EMPLOYES.NO_EMPLOYE = a_no_emloye;
if SQL%NOTFOUND then
raise e_Employe;
end if;
END Supprimer;
--------------- PROCEDURE Augmenter ---------------------PROCEDURE Augmenter
( a_no_emloye EMPLOYES.NO_EMPLOYE%TYPE,
a_salaire
EMPLOYES.SALAIRE%TYPE :=0 )
IS
v_salaire EMPLOYES.SALAIRE%TYPE;
BEGIN
SELECT SALAIRE INTO v_salaire FROM EMPLOYES
WHERE NO_EMPLOYE = a_no_emloye;
case
when a_salaire = 0 then
v_salaire := v_avg_salaire;
when a_salaire <= v_salaire then
raise e_Salaire;
else
v_salaire := a_salaire;
end case;
END Augmenter;
BEGIN
12-53
12-54
Atelier 10.1
Les dclencheurs
Questions
1.
Exercice n1
C, G, H
12-55
Dclencheur cr.
SQL> SELECT REF_PRODUIT, UNITES_STOCK, SUM(UNITES_STOCK) OVER ()
2 FROM PRODUITS
3 WHERE CODE_CATEGORIE = 2;
REF_PRODUIT UNITES_STOCK SUM(UNITES_STOCK)OVER()
----------- ------------ ----------------------3
13
701
4
53
701
6
120
701
8
200
701
66
4
701
77
32
701
5
0
701
15
39
701
44
27
701
61
113
701
63
24
701
65
76
701
12 ligne(s) slectionne(s).
SQL> UPDATE PRODUITS
2 SET UNITES_STOCK = 10
3 WHERE REF_PRODUIT = 3;
UPDATE PRODUITS
*
ERREUR la ligne 1 :
ORA-20000: Le volume total d'une des categories : 1,3,5,7 est > 350
ORA-06512: "STAGIAIRE.PRODUITSVOLUMEMAXSTOCK", ligne 8
ORA-04088: erreur lors d'excution du dclencheur
'STAGIAIRE.PRODUITSVOLUMEMAXSTOCK'
SQL> SELECT REF_PRODUIT, UNITES_STOCK, SUM(UNITES_STOCK) OVER ()
2 FROM PRODUITS
3 WHERE CODE_CATEGORIE = 2;
REF_PRODUIT UNITES_STOCK SUM(UNITES_STOCK)OVER()
----------- ------------ ----------------------3
13
701
...
Crez un dclencheur sur la table EMPLOYES qui empche toute opration si elle ne
seffectue pendant les heurs de travail.
SQL> CREATE OR REPLACE TRIGGER ContrainteTrancheHoraire
2 BEFORE INSERT OR UPDATE OR DELETE ON EMPLOYES
3 DECLARE
12-56
Dclencheur cr.
SQL>
SQL> UPDATE EMPLOYES SET SALAIRE = SALAIRE *1.1;
4 2
UPDATE EMPLOYES SET SALAIRE = SALAIRE *1.1
*
ERREUR la ligne 1 :
ORA-20000: L'application ne peut pas tre modifie hors des heures de
travail.
jeudi
juillet
2006 02:42:06
ORA-06512: "STAGIAIRE.CONTRAINTETRANCHEHORAIRE", ligne 8
ORA-04088: erreur lors d'excution du dclencheur
'STAGIAIRE.CONTRAINTETRANCHEHORAIRE'
Exercice n2
Crez une squence qui commence avec le dernier numro demploy se trouvant dans
la table EMPLOYES. Ensuite, crez un dclencheur qui initialise le NO_EMPLOYE
avec la valeur suivante de la squence sil na pas t renseign. Dans le mme
dclencheur, testez si le champ REND_COMPTE est correctement initialis, avec une
valeur dun employ existant, sinon vous linitialisez avec la mme valeur que
NO_EMPLOYE.
SQL> SET HEADING OFF
SQL> SET ECHO OFF
SQL> SET FEEDBACK OFF
SQL> SET PAGESIZE 0
SQL> SET TERM OFF
SQL> SPOOL C:\CREATE_S_EmployesID.SQL
SQL> SELECT 'CREATE SEQUENCE S_EmployesID START WITH '||
2
MAX(NO_EMPLOYE)||' INCREMENT BY 1;' "--"
3 FROM EMPLOYES;
CREATE SEQUENCE S_EmployesID START WITH 9 INCREMENT BY 1;
SQL> SELECT 'SELECT S_EmployesID.NEXTVAL FROM DUAL;' FROM DUAL;
SELECT S_EmployesID.NEXTVAL FROM DUAL;
SQL> SPOOL OFF
SQL> @C:\CREATE_S_EmployesID.SQL
SQL> SET TERM ON
SQL> SET HEADING ON
SQL> SET ECHO ON
12-57
EMPLOYES
EMPLOYES
12-58
Table cre.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Dclencheur cr.
SQL> DELETE DETAILS_COMMANDES
2 WHERE REF_PRODUIT = 1;
32 ligne(s) supprime(s).
SQL> DELETE PRODUITS
2 WHERE REF_PRODUIT = 1;
1 ligne supprime.
SQL> UPDATE PRODUITS
2 SET PRIX_UNITAIRE = PRIX_UNITAIRE*1.1
3 WHERE REF_PRODUIT IN (2,5,9);
3 ligne(s) mise(s) jour.
SQL> SELECT REF_PRODUIT, NOM_PRODUIT, PRIX_UNITAIRE
2 FROM PRODUITS_ARCHIVE;
12-59
NOM_PRODUIT
PRIX_UNITAIRE
---------------------------------------- ------------Chang
95
Chef Anton's Gumbo Mix
106
Mishi Kobe Niku
485
3 ligne(s) slectionne(s).
SQL> SELECT REF_PRODUIT, NOM_PRODUIT, PRIX_UNITAIRE
2 FROM PRODUITS_POUBELLE ;
REF_PRODUIT NOM_PRODUIT
PRIX_UNITAIRE
----------- ---------------------------------------- ------------1 Chai
90
1 ligne slectionne.
SQL> ROLLBACK;
Annulation (rollback) effectue.
SQL> SELECT REF_PRODUIT, NOM_PRODUIT, PRIX_UNITAIRE
2 FROM PRODUITS_POUBELLE ;
aucune ligne slectionne
SQL> SELECT REF_PRODUIT, NOM_PRODUIT, PRIX_UNITAIRE
2 FROM PRODUITS_ARCHIVE;
aucune ligne slectionne
12-60
Dclencheur cr.
12-61
Atelier 11.1
Lapproche objet
Questions
1.
C, F
2.
Pour lobjet T1 cr avec la syntaxe prcdente, quels sont les blocs qui
peuvent tre compils ?
A. DECLARE v1 T1; BEGIN v1.a1 := 1; v1.m1;END;
B. DECLARE v1 T1; BEGIN v1.m1; END;
C. DECLARE v1 T1 := T1(1,2); BEGIN v1.m1;END;
12-62
A, B, G
Pour les mmes choix que la question prcdente, quels sont les blocs qui
affichent la chane suivante 'Objet T1 a1 :1 a2 :1' ?
Rponse :
4.
D, F
Pour les mmes choix que la question prcdente, quels sont les blocs qui
affichent la chane suivante 'Objet T1 a1 :1 a2 :2' ?
Rponse :
Exercice n1
C, E
Crez un type de tableau imbrique 't_DetCommObj' qui stocke des objets de type
'DetCommObj'.
SQL> CREATE OR REPLACE TYPE t_DetCommObj IS TABLE OF DetCommObj;
2 /
Type cr.
12-63
RETURN
MEMBER
MEMBER
MEMBER
MEMBER
RETURN
MEMBER
RETURN
MEMBER
CODE_CLIENT
CHAR
,
NO_EMPLOYE
NUMBER ,
DATE_COMMANDE
DATE
:= SYSDATE,
DATE_ENVOI
DATE
:= NULL,
PORT
NUMBER := NULL)
SELF AS RESULT,
PROCEDURE AfficheCommande,
PROCEDURE AfficheListeProduits,
PROCEDURE AjoutDeProduit(
REF_PRODUIT
NUMBER ,
PRIX_UNITAIRE NUMBER ,
QUANTITE
NUMBER ,
REMISE
FLOAT := 0),
FUNCTION MontantCommande
NUMBER,
FUNCTION VerifieNotRefProduit(a_refprod NUMBER)
BOOLEAN,
PROCEDURE EnvoisDeCommande
);
/
Type cr.
12-64
SELF.NO_COMMANDE
:= NO_COMMANDE;
SELF.CODE_CLIENT
:= CODE_CLIENT;
SELF.NO_EMPLOYE
:= NO_EMPLOYE;
SELF.DATE_COMMANDE
:= DATE_COMMANDE;
SELF.DATE_ENVOI
:= DATE_ENVOI;
SELF.PORT
:= PORT;
RETURN;
END CommandeObj;
---------------------------------------------------------------MEMBER PROCEDURE AfficheCommande
--------------------------------------------------------------MEMBER PROCEDURE AfficheCommande
IS
BEGIN
dbms_output.put_line('----------------------------');
dbms_output.put_line('NO_COMMANDE
= '||NO_COMMANDE);
dbms_output.put_line('CODE_CLIENT
= '||CODE_CLIENT);
dbms_output.put_line('NO_EMPLOYE
= '||NO_EMPLOYE);
dbms_output.put_line('DATE_COMMANDE = '||DATE_COMMANDE);
dbms_output.put_line('DATE_ENVOI
= '||DATE_ENVOI);
dbms_output.put_line('PORT
= '||PORT);
dbms_output.put_line('Montant Commande = '||
LTRIM((TO_CHAR(MontantCommande,'999G999G999D00U'))));
dbms_output.put_line('----------------------------');
AfficheListeProduits;
END AfficheCommande;
---------------------------------------------------------------MEMBER PROCEDURE AfficheListeProduits
--------------------------------------------------------------MEMBER PROCEDURE AfficheListeProduits
IS
v_indx INTEGER;
BEGIN
v_indx := ListDetCommObj.FIRST;
WHILE v_indx <= ListDetCommObj.LAST
LOOP
dbms_output.put_line('----------------------------');
dbms_output.put_line('--REF_PRODUIT
= '||
ListDetCommObj(v_indx).REF_PRODUIT);
dbms_output.put_line('----------------------------');
dbms_output.put_line('-PRIX_UNITAIRE = '||
ListDetCommObj(v_indx).PRIX_UNITAIRE);
dbms_output.put_line('-QUANTITE
= '||
ListDetCommObj(v_indx).QUANTITE);
dbms_output.put_line('-REMISE
= '||
ListDetCommObj(v_indx).REMISE);
v_indx := ListDetCommObj.NEXT(v_indx);
dbms_output.put_line('----------------------------');
END LOOP;
END AfficheListeProduits;
---------------------------------------------------------------MEMBER FUNCTION VerifieNotRefProduit
--------------------------------------------------------------MEMBER FUNCTION VerifieNotRefProduit(a_refprod NUMBER)
12-65
12-66
RETURN BOOLEAN
IS
v_refprod PRODUITS.REF_PRODUIT%TYPE;
BEGIN
SELECT REF_PRODUIT INTO v_refprod FROM PRODUITS
WHERE REF_PRODUIT = a_refprod;
RETURN FALSE;
EXCEPTION
when NO_DATA_FOUND then RETURN TRUE;
END VerifieNotRefProduit;
---------------------------------------------------------------MEMBER PROCEDURE AjoutDeProduit
--------------------------------------------------------------MEMBER PROCEDURE AjoutDeProduit(
REF_PRODUIT
NUMBER ,
PRIX_UNITAIRE NUMBER ,
QUANTITE
NUMBER ,
REMISE
FLOAT := 0)
IS
BEGIN
if (REF_PRODUIT IS NULL OR
PRIX_UNITAIRE IS NULL OR
QUANTITE IS NULL ) AND
VerifieNotRefProduit(REF_PRODUIT)
then
RETURN;
end if;
if ListDetCommObj IS NULL then
ListDetCommObj := t_DetCommObj(
DetCommObj(REF_PRODUIT,PRIX_UNITAIRE,QUANTITE,REMISE));
else
ListDetCommObj.EXTEND;
ListDetCommObj(ListDetCommObj.LAST) :=
DetCommObj(REF_PRODUIT,PRIX_UNITAIRE,QUANTITE,REMISE);
end if;
END AjoutDeProduit;
---------------------------------------------------------------MEMBER FUNCTION MontantCommande
--------------------------------------------------------------MEMBER FUNCTION MontantCommande
RETURN NUMBER
IS
v_indx INTEGER;
v_montant DETAILS_COMMANDES.PRIX_UNITAIRE%TYPE := 0;
BEGIN
v_indx := ListDetCommObj.FIRST;
WHILE v_indx <= ListDetCommObj.LAST
LOOP
v_montant := v_montant + (
ListDetCommObj(v_indx).PRIX_UNITAIRE *
ListDetCommObj(v_indx).QUANTITE);
v_indx := ListDetCommObj.NEXT(v_indx);
END LOOP;
RETURN v_montant;
END MontantCommande;
---------------------------------------------------------------MEMBER PROCEDURE EnvoisDeCommande
--------------------------------------------------------------MEMBER PROCEDURE EnvoisDeCommande
IS
CURSOR c_prod( a_ref_prod NUMBER) IS
SELECT NVL(UNITES_STOCK,0) UNITES_STOCK,
NVL(UNITES_COMMANDEES,0) UNITES_COMMANDEES
FROM PRODUITS
WHERE REF_PRODUIT = a_ref_prod
FOR UPDATE OF UNITES_COMMANDEES, UNITES_COMMANDEES;
v_indx INTEGER;
BEGIN
v_indx := ListDetCommObj.FIRST;
WHILE v_indx <= ListDetCommObj.LAST
LOOP
for v_p in c_prod(ListDetCommObj(v_indx).REF_PRODUIT)
loop
if v_p.UNITES_STOCK < ListDetCommObj(v_indx).QUANTITE
then
v_p.UNITES_COMMANDEES := v_p.UNITES_COMMANDEES +
ListDetCommObj(v_indx).QUANTITE v_p.UNITES_STOCK;
v_p.UNITES_STOCK := 0;
else
v_p.UNITES_STOCK := v_p.UNITES_STOCK ListDetCommObj(v_indx).QUANTITE;
end if;
UPDATE PRODUITS
SET UNITES_STOCK
= v_p.UNITES_STOCK,
UNITES_COMMANDEES = v_p.UNITES_COMMANDEES
WHERE CURRENT OF c_prod;
end loop;
v_indx := ListDetCommObj.NEXT(v_indx);
END LOOP;
COMMIT;
END EnvoisDeCommande;
END;
/
SQL> DECLARE
2
v_CommandeObj CommandeObj := CommandeObj(1,'ALFKI',4);
12-67
Exercice n2
Pour pouvoir stocker des enregistrements de type 'CommandeObj' dans une table,
vous devez crer la mthode MAP qui retourne la cl de la commande en
occurrence NO_COMMANDE.
SQL> CREATE OR REPLACE TYPE CommandeObj IS OBJECT (
...
17 MAP MEMBER FUNCTION CleCommande
18
RETURN NUMBER,
...
12-68
DECLARE
v_CommandeObj CommandeObj;
BEGIN
for comm in ( SELECT * FROM COMMANDES ) loop
v_CommandeObj := CommandeObj(
comm.NO_COMMANDE,comm.CODE_CLIENT,comm.NO_EMPLOYE,
comm.DATE_COMMANDE,comm.DATE_ENVOI,comm.PORT );
for det in ( SELECT * FROM DETAILS_COMMANDES
WHERE NO_COMMANDE = comm.NO_COMMANDE) loop
v_CommandeObj.AjoutDeProduit( det.REF_PRODUIT,
det.PRIX_UNITAIRE,det.QUANTITE,det.REMISE);
end loop;
INSERT INTO TCommandeObj VALUES v_CommandeObj;
end loop;
COMMIT;
END;
/
DECLARE
v_CommandeObj CommandeObj;
BEGIN
SELECT VALUE(A) INTO v_CommandeObj FROM TCommandeObj A
WHERE A.NO_COMMANDE = 215094;
v_CommandeObj.AfficheCommande;
end;
/
12-69
12-70
Atelier 12.1
Exercice n1
DECLARE
vnom_prod PRODUITS.NOM_PRODUIT%TYPE;
BEGIN
SELECT NOM_PRODUIT INTO vnom_prod FROM PRODUITS
WHERE REF_PRODUIT = 1;
DBMS_OUTPUT.ENABLE;
DBMS_OUTPUT.PUT_LINE( vnom_prod);
END;
/
DECLARE
ligne varchar(32767);
nombre NUMBER ;
BEGIN
DBMS_OUTPUT.GET_LINE( ligne, nombre);
UPDATE PRODUITS SET UNITES_STOCK = UNITES_STOCK*1.1
WHERE NOM_PRODUIT = ligne;
END;
/
12-71
Exercice n2
UTL_FILE
DECLARE
v_nom_rep
v_nom_fic
VARCHAR2(255):= 'UTL_FILE_REPERTOIRE';
VARCHAR2(255):= 'F_CLIENTS'||
TO_CHAR(SYSDATE,'YYYYMMDD')||'.TXT';
v_tampon
VARCHAR2(32766);
v_fichier UTL_FILE.FILE_TYPE;
BEGIN
v_fichier := UTL_FILE.FOPEN( v_nom_rep, v_nom_fic,'W');
if UTL_FILE.IS_OPEN(v_fichier) then
for r_emp in ( SELECT SOCIETE,ADRESSE,VILLE,
CODE_POSTAL,PAYS from CLIENTS)
loop
UTL_FILE.PUTF( v_fichier,'%s;%s;%s;%s;%s\n',
r_emp.SOCIETE,r_emp.ADRESSE,
r_emp.VILLE,r_emp.CODE_POSTAL,r_emp.PAYS);
end loop;
UTL_FILE.FCLOSE(v_fichier);
end if;
END;
/
Exercice n3
DBMS_JOB
Placez les deux procdures de mise jour du modle toile dans la file d'attente des
travaux. La frquence dexcution de ces deux traitements doit tre hebdomadaire.
SQL> DECLARE
2
v_travail_no NUMBER;
3 BEGIN
4
DBMS_JOB.SUBMIT( JOB
=>v_travail_no,
5
WHAT
=>'STAGIAIRE.MAJ_MODEL_ETOILE;',
6
NEXT_DATE =>SYSDATE,
7
INTERVAL =>'SYSDATE + 1');
8
DBMS_OUTPUT.PUT_LINE('MAJ_MODEL_ETOILE');
12-72
Exercice n3
DBMS_METADATA
12-73