Sie sind auf Seite 1von 0

Licence SMI 2007 2008 B.

OUAHBI
PL/SQL

Exercice 1 :
Parmi les dclarations de variables suivantes, dterminer celles qui sont incorrectes :
A - DECLARE
v_id NUMBER(4);
Correcte
B - DECLARE
v_x,v_y,v_z VARCHAR2(10);
Incorrecte : un seul identifiant par ligne
C - DECLARE
v_date_naissance DATE NOT NULL;
Incorrecte : une valeur NOT NULL doit tre initialise
D - DECLARE
v_en_stock BOOLEAN := 1;
Incorrecte : 1 nest pas une valeur boolenne
E - DECLARE
emp_record emp_record_type;
Incorrecte : EMP_RECORD_TYPE doit tre dclar
F - DECLARE
TYPE type_table_nom IS TABLE OF VARCHAR2(20)
INDEX BY BINARY_INTEGER;
dept_table_nom type_table_nom;
Correcte

Exercice 2 :
1 - Crer un bloc PL/SQL pour insrer un nouveau dpartement dans la table DEPARTEMENTS
a) Utiliser la squence DEPT_ID_SEQ pour gnrer un numro de dpartement. Crer un paramtre pour le nom
du dpartement. Laisser le numro de rgion NULL.
Fichier p2q1.sql
ACCEPT p_dept_nom PROMPT Entrer un nom de dpartement :
BEGIN
INSERT INTO departements(id, nom, region_id)
VALUES (dept_id_seq.NEXTVAL, &p_dept_nom, NULL);
COMMIT;
END;
/
b) Excuter le bloc PL/SQL avec la valeur Sant pour le nom du dpartement.
SQL> start p2q1
Entrer un nom de dpartement : Sant
PL/SQL procedure successfully completed.
c) Afficher le nouveau dpartement cr
SQL> SELECT * FROM departements
2 WHERE nom = 'Sant';
ID NOM REGION_ID
--------- ------------------------- ---------
82 Sant
2 - Crer un bloc PL/SQL pour supprimer le dpartement cr prcdemment
a) Crer un paramtre pour le numro de dpartement. Faire afficher lcran le nombre de lignes affectes.
Fichier p2q2.sql
ACCEPT p_dept_id PROMPT 'Entrer un numro de dpartement : '
VARIABLE g_mess VARCHAR2(30)
DECLARE
v_resultat NUMBER(2);
BEGIN
DELETE FROM departements
WHERE id = &p_dept_id;
v_resultat := SQL%ROWCOUNT;
:g_mess := TO_CHAR(v_resultat)||' ligne(s) supprime(s).';
COMMIT;
END;
/
PRINT g_mess
b) Tester le bloc. Que se passe-t-il si on saisit un numro de dpartement qui nexiste pas?
SQL> start p2q2
Entrer un numro de dpartement : 134
PL/SQL procedure successfully completed.
G_MESS
--------------------------------
0 ligne(s) supprime(s).
Si on saisit un numro de dpartement qui a des employs?
SQL> start p2q2
Entrer un numro de dpartement : 31
DECLARE
*
ERROR at line 1:
ORA-02292: integrity constraint (BOHEZ.EMPLOYES_DEPT_ID_FK) violated - child record found
ORA-06512: at line 4
c) Tester le bloc avec le dpartement Sant (82)
SQL> start p2q2
Entrer un numro de dpartement : 82
PL/SQL procedure successfully completed.
G_MESS
--------------------------------
1 ligne(s) supprime(s).
d) Vrifier que le dpartement nexiste plus
SQL> SELECT *
2 FROM departements
3 WHERE id = 82;
no rows selected

Exercice 3 :
1 - Crer un bloc PL/SQL permettant de mettre jour le pourcentage de commission dun employ en fonction du
total de ses ventes
Cet exercice ncessite la suppression de la contrainte sur la colonne commission de la table EMPLOYES :
SQL> ALTER TABLE employes
2 DROP CONSTRAINT employes_commission_ck;
a) Crer un paramtre qui reoit un numro demploy
Trouver la somme totale de toutes les commandes traites par cet employ
Mettre jour le pourcentage de commission de lemploy :
- si la somme est infrieure 100,000 passer la commission 10
- si la somme est comprise entre 100,000 et 1,000,000 inclus passer la commission 15
- si la somme excde 1,000,000 passer la commission 20
- si aucune commande nexiste pour cet employ, mettre la commission 0
Valider la modification (commit)
Fichier p3q1.sql.
ACCEPT p_id PROMPT 'Entrer un numro de vendeur : '
DECLARE
v_somme_total NUMBER(11,2);
v_comm employes.commission%TYPE;
BEGIN
SELECT SUM(total)
INTO v_somme_total
FROM commandes
WHERE vendeur_id = &p_id;

IF v_somme_total < 100000 THEN
v_comm := 10;
ELSIF v_somme_total <= 1000000 THEN
v_comm := 15;
ELSIF v_somme_total > 1000000 THEN
v_comm := 20;
ELSE
v_comm := 0;
END IF;
UPDATE employes

SET commission = v_comm
WHERE id = &p_id;
COMMIT;
END;
/
b) Tester le bloc et visualiser les rsultats (on teste avec les employs 1,11,12,14)
SQL> SELECT id, commission
2 FROM employes
3 WHERE id IN (1,11,12,14);
ID COMMISSION
--------- ----------
14 10
12 15
11 20
1 0
2 - Crer un bloc PL/SQL qui boucle pour chaque rgion (le numro des rgions va de 1 5) afin de modifier le
code de solvabilit de tous les clients. Ne pas valider (pas de commit).
Si le numro de rgion est pair mettre la solvabilit EXCELLENTE (mme si elle lest dj), sinon mettre
BONNE pour les numros de rgion impairs.
Une fois les lignes modifies, trouvez combien de lignes ont t mises jour.
Afficher les rsultats suivants en fonction du nombre de lignes modifies :
G Si moins de trois lignes ont t modifies, afficher : Moins de trois lignes ont t
modifies pour la rgion x (x tant le numro de la rgion).
G Sinon afficher : y lignes ont t modifies pour la rgion x(y tant le nombre de lignes
modifies).
Annuler les modifications (rollback).
Fichier p3q2.sql.
VARIABLE g_mess VARCHAR2(500)
DECLARE
v_sortie VARCHAR2(500);
v_modifies NUMBER(2);
v_solvable VARCHAR2(25);
c_peu CONSTANT VARCHAR2(100)
:= 'Moins de 3 lignes ont t modifies pour la rgion ';

BEGIN
FOR i IN 1..5 LOOP

IF MOD(i,2) <> 0 THEN
v_solvable := 'EXCELLENTE';
ELSE
v_solvable := 'BONNE';
END IF;

UPDATE clients
SET solvabilite = v_solvable
WHERE region_id = i;
v_modifies := SQL%ROWCOUNT;

IF v_modifies < 3 THEN
v_sortie := v_sortie||c_peu||TO_CHAR(i)||CHR(10);
ELSE
v_sortie := v_sortie||TO_CHAR(v_modifies)||
' lignes ont t modifies pour la rgion '||TO_CHAR(i)||CHR(10);
END IF;
END LOOP;
:g_mess := v_sortie;
END;
/
PRINT g_mess

Exercice 4 :
Crer un bloc PL/SQL qui dtermine les employs de plus haut salaire.
a) Crer pour cet exercice une nouvelle table pour stocker les employs et leurs salaires
SQL> CREATE TABLE meilleurs
2 (nom VARCHAR2(25),
3 salaire NUMBER(11,2));
b) Utiliser un paramtre pour prendre une valeur n en entre pour identifier les n meilleurs.
Ecrire une boucle WHILE avec curseur pour rcuprer le nom et salaire des n meilleurs employs selon leur
salaire dans la table EMPLOYES
Enregistrer les noms et salaires dans la table MEILLEURS.
On suppose quaucun employ na le mme salaire quun autre.
c) Tester le bloc avec diffrents cas tels que n=0 ou n suprieur au nombre total demploys (25).
Vider la table MEILLEURS aprs chaque test.
Fichier p4q1.sql.
ACCEPT p_n PROMPT 'Entrer une valeur numrique : '
DECLARE
CURSOR emp_cursor IS
SELECT nom, salaire
FROM employes
WHERE salaire IS NOT NULL
ORDER BY salaire DESC;
emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
FOR i IN 1..&p_n
LOOP
FETCH emp_cursor INTO emp_record;
INSERT INTO meilleurs(nom, salaire)
VALUES (emp_record.nom,emp_record.salaire);
END LOOP;
CLOSE emp_cursor;
COMMIT;
END;
/
SELECT nom,TO_CHAR(salaire,'fm$9,999,999') salaire FROM meilleurs;
TRUNCATE TABLE meilleurs
Test du bloc avec n=4
SQL> start p4q1
Entrer une valeur numrique : 4
PL/SQL procedure successfully completed.
NOM SALAIRE
----------------------------- -------------
Velasquez $2,500
Ropeburn $1,550
Nguyen $1,525
Sedeghi $1,515
Table truncated.
Test du bloc avec n=0
SQL> start p4q1
Entrer une valeur numrique : 0
PL/SQL procedure successfully completed.
no rows selected
Table truncated.
Test du bloc avec n=30
SQL> START p4q1
Entrer une valeur numrique : 30
PL/SQL procedure successfully completed.
NOM SALAIRE
------------------------- -----------
Velasquez $2,500
Ropeburn $1,550
Nguyen $1,525
Sedeghi $1,515
Giljum $1,490
Ngao $1,450
Quick-To-See $1,450
Dumas $1,450
Nagayama $1,400
Maduro $1,400
Magee $1,400
Havel $1,307
Catchpole $1,300
Menchu $1,250
Urguhart $1,200
Nozaki $1,200
Biri $1,100
Schwartz $1,100
Smith $940
Dancs $860
Markarian $850
Chang $800
Patel $795
Patel $795
Newman $750
Newman $750
Newman $750
Newman $750
Newman $750
Newman $750
30 rows selected.
Table truncated.

Exercice 5 :
Modifier le bloc PL/SQL fourni pour grer les exceptions.
Le traitement essaie de mettre jour des numros de rgion pour des dpartements existants.
a) Charger le fichier p5qa.sql.
ACCEPT p_dept_id PROMPT 'Numro de dpartement : '
ACCEPT p_nom_region PROMPT 'Nom de rgion : '
VARIABLE g_mess VARCHAR2(50)
DECLARE
v_region_id regions.id%TYPE;
BEGIN
SELECT id
INTO v_region_id
FROM regions
WHERE UPPER(nom)=UPPER('&p_nom_region');
UPDATE departements
SET region_id=v_region_id
WHERE id = &p_dept_id;
:g_mess := 'Le dpartement : '||TO_CHAR(&p_dept_id)||
est affect la rgion '||TO_CHAR(v_region_id);
COMMIT;
END;
/
PRINT g_mess
b) Excuter le bloc avec comme valeur 50 pour le numro de dpartement et US pour le nom de rgion.
SQL> start p5qa
Numro de dpartement : 50
Nom de rgion : US
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 5
G_MESS
-----------------------------------------------------------------
c) Sauvegarder le fichier p5qa.sql sous le nom p5q1.sql. Modifier p5q1.sql pour crire un traitement dexception
pour lanomalie constate afin de passer un message lutilisateur lorsque la rgion spcifie nexiste pas.
ACCEPT p_dept_id PROMPT 'Numro de dpartement : '
ACCEPT p_nom_region PROMPT 'Nom de rgion : '
VARIABLE g_mess VARCHAR2(50)
DECLARE
v_region_id regions.id%TYPE;
BEGIN
SELECT id
INTO v_region_id
FROM regions
WHERE UPPER(nom)=UPPER('&p_nom_region');
UPDATE departements
SET region_id=v_region_id
WHERE id = &p_dept_id;
:g_mess := 'Le dpartement : '||TO_CHAR(&p_dept_id)||
est affect la rgion '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : rgion inexistante.';
END;
/
PRINT g_mess
SQL> start p5q1
Numro de dpartement : 50
Nom de rgion : US
PL/SQL procedure successfully completed.
G_MESS
---------------------------------------------------------------------
US : rgion inexistante.
d) Excuter le bloc avec comme valeur 31 pour le numro de dpartement et Asie pour le nom de rgion.
SQL> START p5q1
Numro de dpartement : 31
Nom de rgion : Asie
DECLARE
*
ERROR at line 1:
ORA-00001: unique constraint (BOHEZ.DEPARTEMENTS_NOM_ET_REGION_UK) violated
ORA-06512: at line 9
G_MESS
---------------------------------------------------------------------------
e) Ecrire un traitement dexception pour lanomalie constate afin de passer un message lutilisateur lorsque la
rgion spcifie est dj rfrence par un dpartement du mme nom
ACCEPT p_dept_id PROMPT 'Numro de dpartement : '
ACCEPT p_nom_region PROMPT 'Nom de rgion : '
VARIABLE g_mess VARCHAR2(80)
DECLARE
v_dept VARCHAR2(20);
v_region_id regions.id%TYPE;
BEGIN
SELECT id
INTO v_region_id
FROM regions
WHERE UPPER(nom)=UPPER('&p_nom_region');
UPDATE departements
SET region_id=v_region_id
WHERE id = &p_dept_id;
:g_mess := 'Le dpartement : '||TO_CHAR(&p_dept_id)||
est affect la rgion '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : rgion inexistante.';
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
SELECT nom||' (N'||TO_CHAR(id)||')'
INTO v_dept
FROM departements
WHERE region_id = v_region_id
AND nom =
(SELECT nom
FROM departements
WHERE id = &p_dept_id);
:g_mess := 'Il existe dj un dpartement '||v_dept||
' pour la rgion '||'&p_nom_region';
END;
/
PRINT g_mess
e) Suite
SQL> start p5q1
Numro de dpartement : 31
Nom de rgion : Asie
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Il existe dj un dpartement Ventes (N34) pour la rgion Asie
f) Excuter le bloc avec comme valeur 99 pour le numro de dpartement et Europe pour le nom de la rgion
SQL> start p5q1
Numro de dpartement : 99
Nom de rgion : Europe
PL/SQL procedure successfully completed.
G_MESS
----------------------------------------------------------------------------------
Le dpartement : 99 est affect la rgion 5
Anomalie constate : la procdure ne remarque pas que le dpartement 99 nexiste pas.
g) Ecrire un traitement dexception pour lanomalie constate afin de passer un message lutilisateur lorsque le
numro de dpartement spcifi nexiste pas.
Rappel : penser utiliser lattribut SQL%NOTFOUND et dclencher une exception manuellement
ACCEPT p_dept_id PROMPT 'Numro de dpartement : '
ACCEPT p_nom_region PROMPT 'Nom de rgion : '
VARIABLE g_mess VARCHAR2(80)
DECLARE
v_dept VARCHAR2(20);
v_region_id regions.id%TYPE;
e_count EXCEPTION;
BEGIN
SELECT id
INTO v_region_id
FROM regions
WHERE UPPER(nom)=UPPER('&p_nom_region');
UPDATE departements
SET region_id=v_region_id
WHERE id = &p_dept_id;
IF SQL%NOTFOUND THEN
RAISE e_count;
END IF;
:g_mess := 'Le dpartement : '||TO_CHAR(&p_dept_id)||
' est affect la rgion '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : rgion inexistante.';
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
SELECT nom||' (N'||TO_CHAR(id)||')'
INTO v_dept
FROM departements
WHERE region_id = v_region_id
AND nom =
(SELECT nom
FROM departements
WHERE id = &p_dept_id);
:g_mess := 'Il existe dj un dpartement '||v_dept||
' pour la rgion '||'&p_nom_region';
WHEN e_count THEN
ROLLBACK;
:g_mess := 'Le dpartement numro '||TO_CHAR(&p_dept_id)||' n''existe pas.';
END;
/
PRINT g_mess
g) Suite
SQL> start p5q1
Numro de dpartement : 99
Nom de rgion : Europe
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Le dpartement numro 99 n'existe pas

Structure et Donnes des Tables

SQL>desc departements
Name Null? Type
-------------------------------------- ---------------- --------------------------
ID NOT NULL NUMBER(7)
NOM NOT NULL VARCHAR2(25)
REGION_ID NUMBER(7)

SQL>SELECT * FROM departements
ID NOM REGION_ID
------ ------------------------------------------ -----------------
10 Finance 1
31 Ventes 1
32 Ventes 2
33 Ventes 3
34 Ventes 4
35 Ventes 5
41 Oprations 1
42 Oprations 2
43 Oprations 3
44 Oprations 4
45 Oprations 5
50 Administration 1





SQL>desc Commandes
Name Null? Type
----------------------- --------------- -------------------------
ID NOT NULL NUMBER(7)
CLIENT_ID NOT NULL NUMBER(7)
DATE_COMM DATE
DATE_EXP DATE
VENDEUR_ID NUMBER(7)
TOTAL NUMBER(11,2)
TYPE_PAIEMENT VARCHAR2(8)
COMM_REMPLIE VARCHAR2(1)

SQL>desc employes
Name Null? Type
----------------------------- ------------------------- ----------------------------
ID NOT NULL NUMBER(7)
NOM NOT NULL VARCHAR2(25)
PRENOM VARCHAR2(25)
USERID VARCHAR2(8)
DATE_EMB DATE
COMMENTAIRES VARCHAR2(255)
RESPONSABLE_ID NUMBER(7)
POSTE VARCHAR2(25)
DEPT_ID NUMBER(7)
SALAIRE NUMBER(11,2)
COMMISSION NUMBER(4,2)

SQL>SELECT * FROM employes
ID NOM PRENOM USERID DATE_EMB C M POSTE DE SAL CO
--- ------------ ------------ ---------- ---------------- -- -- ------------------ ---- ------ ---
1 Velasquez Carmen cvelasqu 03-03-90 Prsident 50 2500
2 Ngao LaDoris lngao 08-03-90 1 VP, Oprations 41 1450
3 Nagayama Midor mnagayam 17-06-91 1 VP, Ventes 31 1400
4 Quick-To-See Mark mquickto 07-04-90 1 VP, Finance 10 1450
5 Ropeburn Audrey aropebur 04-03-90 1 VP, Administrat. 50 1550
6 Urguhart Molly murguhar 18-01-91 2 Resp. Magasin 41 1200
7 Menchu Roberta rmenchu 14-05-91 2 Resp. Magasin 42 1250
8 Biri Ben bbiri 07-04-90 2 Resp. Magasin 43 1100
9 Catchpole Antoinette acatchpo 09-02-92 2 Resp. Magasin 44 1300
10 Havel Marta mhavel 27-02-91 2 Resp. Magasin 45 1307
11 Magee Colin cmagee 14-05-90 3 Reprsentant 31 1400 10
12 Giljum Henry hgiljum 18-01-92 3 Reprsentant 32 1490 12.5
13 Sedeghi Yasmin ysedeghi 18-02-91 3 Reprsentant 33 1515 10
14 Nguyen Mai mnguyen 22-01-92 3 Reprsentant 34 1525 15
15 Dumas Andr adumas 09-10-91 3 Reprsentant 35 1450 17.5
16 Maduro Elena emaduro 07-02-92 6 Magasinier 41 1400
17 Smith George gsmith 08-03-90 6 Magasinier 41 940
18 Nozaki Akira anozaki 02-02-91 7 Magasinier 42 1200
19 Patel Vikram vpatel 06-08-91 7 Magasinier 42 795
20 Newman Chad cnewman 21-07-91 8 Magasinier 43 750
21 Markarian Alexander amarkari 26-05-91 8 Magasinier 43 850
22 Chang Eddie echang 30-11-90 9 Magasinier 44 800
23 Patel Radha rpatel 17-10-90 9 Magasinier 44 795
24 Dancs Bela bdancs 17-03-91 10 Magasinier 45 860
25 Schwartz Sylvie sschwart 09-05-91 10 Magasinier 45 1100

Das könnte Ihnen auch gefallen