Exercices Corrigés PL/SQL TD SQL Oracle
Exercice 1 :
Parmi les déclarations de variables suivantes, déterminer 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 initialisée
D - DECLARE
v_en_stock BOOLEAN := 1;
Incorrecte : 1 n’est pas une valeur booléenne
E - DECLARE
emp_record emp_record_type;
Incorrecte : EMP_RECORD_TYPE doit être déclaré
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 - Créer un bloc PL/SQL pour insérer un nouveau département dans la table DEPARTEMENTS
a) Utiliser la séquence DEPT_ID_SEQ pour générer un numéro de département. Créer un paramètre pour le nom du département. Laisser le numéro de région à NULL.
Fichier p2q1.sql
ACCEPT p_dept_nom PROMPT ‘Entrer un nom de département : ‘
BEGIN
INSERT INTO departements(id, nom, region_id)
VALUES (dept_id_seq.NEXTVAL, ‘&p_dept_nom’, NULL);
COMMIT;
END;
/
b) Exécuter le bloc PL/SQL avec la valeur “Santé” pour le nom du département.
SQL> start p2q1
Entrer un nom de département : Santé
PL/SQL procedure successfully completed.
c) Afficher le nouveau département créé
SQL> SELECT * FROM departements
2 WHERE nom = 'Santé';
ID NOM REGION_ID
--------- ------------------------- ---------
82 Santé
2 - Créer un bloc PL/SQL pour supprimer le département créé précédemment
a) Créer un paramètre pour le numéro de département. Faire afficher à l’écran le nombre de lignes affectées.
Fichier p2q2.sql
ACCEPT p_dept_id PROMPT 'Entrer un numéro de département : '
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) supprimée(s).';
COMMIT;
END;
/
PRINT g_mess
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) supprimée(s).';
COMMIT;
END;
/
PRINT g_mess
b) Tester le bloc. Que se passe-t-il si on saisit un numéro de département qui n’existe pas?
SQL> start p2q2
Entrer un numéro de département : 134
PL/SQL procedure successfully completed.
G_MESS
--------------------------------
0 ligne(s) supprimée(s).
Si on saisit un numéro de département qui a des employés?
SQL> start p2q2
Entrer un numéro de département : 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 département Santé (82)
SQL> start p2q2
Entrer un numéro de département : 82
PL/SQL procedure successfully completed.
G_MESS
--------------------------------
1 ligne(s) supprimée(s).
d) Vérifier que le département n’existe plus
SQL> SELECT *
2 FROM departements
3 WHERE id = 82;
no rows selected
Exercice 3 :
1 - Créer un bloc PL/SQL permettant de mettre à jour le pourcentage de commission d’un employé en fonction du total de ses ventes
Cet exercice nécessite la suppression de la contrainte sur la colonne commission de la table EMPLOYES :
SQL> ALTER TABLE employes
2 DROP CONSTRAINT employes_commission_ck;
a) Créer un paramètre qui reçoit un numéro d’employé
Trouver la somme totale de toutes les commandes traitées par cet employé
Mettre à jour le pourcentage de commission de l’employé :
- si la somme est inférieure à 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 excède 1,000,000 passer la commission à 20
- si aucune commande n’existe pour cet employé, mettre la commission à 0
Valider la modification (commit)
Fichier p3q1.sql.
ACCEPT p_id PROMPT 'Entrer un numéro 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;
/
UPDATE employes
SET commission = v_comm
WHERE id = &p_id;
COMMIT;
END;
/
b) Tester le bloc et visualiser les résultats (on teste avec les employés 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 - Créer un bloc PL/SQL qui boucle pour chaque région (le numéro des régions va de 1 à 5) afin de modifier le code de solvabilité de tous les clients. Ne pas valider (pas de commit).
Si le numéro de région est pair mettre la solvabilité à EXCELLENTE (même si elle l’est déjà), sinon mettre à BONNE pour les numéros de région impairs.
Une fois les lignes modifiées, trouvez combien de lignes ont été mises à jour.
Afficher les résultats suivants en fonction du nombre de lignes modifiées :
- Si moins de trois lignes ont été modifiées, afficher : ‘Moins de trois lignes ont été modifiées pour la région x’ (x étant le numéro de la région).
- Sinon afficher : ‘y lignes ont été modifiées pour la région x’(y étant le nombre de lignes modifiées).
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é modifiées pour la région ';
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é modifiées pour la région '||TO_CHAR(i)||CHR(10);
END IF;
END LOOP;
:g_mess := v_sortie;
END;
/
PRINT g_mess
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é modifiées pour la région '||TO_CHAR(i)||CHR(10);
END IF;
END LOOP;
:g_mess := v_sortie;
END;
/
PRINT g_mess
Exercice 4 :
Créer un bloc PL/SQL qui détermine les employés de plus haut salaire.
a) Créer pour cet exercice une nouvelle table pour stocker les employés et leurs salaires
SQL> CREATE TABLE meilleurs
2 (nom VARCHAR2(25),
3 salaire NUMBER(11,2));
b) Utiliser un paramètre pour prendre une valeur n en entrée pour identifier les n meilleurs.
Ecrire une boucle WHILE avec curseur pour récupérer le nom et salaire des n meilleurs employés selon leur salaire dans la table EMPLOYES
Enregistrer les noms et salaires dans la table MEILLEURS.
On suppose qu’aucun employé n’a le même salaire qu’un autre.
c) Tester le bloc avec différents cas tels que n=0 ou n supérieur au nombre total d’employés (25).
Vider la table MEILLEURS après chaque test.
Fichier p4q1.sql.
ACCEPT p_n PROMPT 'Entrer une valeur numérique : '
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 numérique : 4
PL/SQL procedure successfully completed.
NOM SALAIRE
----------------------------- -------------
Velasquez $2,500
Ropeburn $1,550
Nguyen $1,525
Sedeghi $1,515
Table truncated.
Entrer une valeur numérique : 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 numérique : 0
PL/SQL procedure successfully completed.
no rows selected
Table truncated.
Test du bloc avec n=30
SQL> START p4q1
Entrer une valeur numérique : 30
PL/SQL procedure successfully completed.
NOM SALAIRE
------------------------- -----------
Velasquez $2,500
Ropeburn $1,550
Nguyen $1,525
Sedeghi $1,515
Giljum $1,490
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 gérer les exceptions.
Le traitement essaie de mettre à jour des numéros de région pour des départements existants.
a) Charger le fichier p5qa.sql.
ACCEPT p_dept_id PROMPT 'Numéro de département : '
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
’ est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
END;
/
PRINT g_mess
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
’ est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
END;
/
PRINT g_mess
b) Exécuter le bloc avec comme valeur 50 pour le numéro de département et US pour le nom de région.
SQL> start p5qa
Numéro de département : 50
Nom de région : 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 d’exception pour l’anomalie constatée afin de passer un message à l’utilisateur lorsque la région spécifiée n’existe pas.
ACCEPT p_dept_id PROMPT 'Numéro de département : '
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
’ est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : région inexistante.';
END;
/
PRINT g_mess
SQL> start p5q1
Numéro de département : 50
Nom de région : US
PL/SQL procedure successfully completed.
G_MESS
---------------------------------------------------------------------
US : région inexistante.
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 département : '||TO_CHAR(&p_dept_id)||
’ est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : région inexistante.';
END;
/
PRINT g_mess
SQL> start p5q1
Numéro de département : 50
Nom de région : US
PL/SQL procedure successfully completed.
G_MESS
---------------------------------------------------------------------
US : région inexistante.
d) Exécuter le bloc avec comme valeur 31 pour le numéro de département et Asie pour le nom de région.
SQL> START p5q1
Numéro de département : 31
Nom de région : Asie
DECLARE
*
ORA-00001: unique constraint (BOHEZ.DEPARTEMENTS_NOM_ET_REGION_UK) violated
ORA-06512: at line 9
G_MESS
---------------------------------------------------------------------------
e) Ecrire un traitement d’exception pour l’anomalie constatée afin de passer un message à l’utilisateur lorsque la région spécifiée est déjà référencée par un département du même nom
ACCEPT p_dept_id PROMPT 'Numéro de département : '
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
’ est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : région 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 déjà un département '||v_dept||
' pour la région '||'&p_nom_region';
END;
/
PRINT g_mess
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 déjà un département '||v_dept||
' pour la région '||'&p_nom_region';
END;
/
PRINT g_mess
SQL> start p5q1
Numéro de département : 31
Nom de région : Asie
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Il existe déjà un département Ventes (N°34) pour la région Asie
Numéro de département : 31
Nom de région : Asie
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Il existe déjà un département Ventes (N°34) pour la région Asie
f) Exécuter le bloc avec comme valeur 99 pour le numéro de département et Europe pour le nom de la région
SQL> start p5q1
Numéro de département : 99
Nom de région : Europe
PL/SQL procedure successfully completed.
G_MESS
----------------------------------------------------------------------------------
Le département : 99 est affecté à la région 5
Numéro de département : 99
Nom de région : Europe
PL/SQL procedure successfully completed.
G_MESS
----------------------------------------------------------------------------------
Le département : 99 est affecté à la région 5
Anomalie constatée : la procédure ne remarque pas que le département 99 n’existe pas.
g) Ecrire un traitement d’exception pour l’anomalie constatée afin de passer un message à l’utilisateur lorsque le numéro de département spécifié n’existe pas.
Rappel : penser à utiliser l’attribut SQL%NOTFOUND et déclencher une exception manuellement
ACCEPT p_dept_id PROMPT 'Numéro de département : '
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
' est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : région inexistante.';
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
SELECT nom||' (N°'||TO_CHAR(id)||')'
ACCEPT p_nom_region PROMPT 'Nom de région : '
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 département : '||TO_CHAR(&p_dept_id)||
' est affecté à la région '||TO_CHAR(v_region_id);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
:g_mess := '&p_nom_region'||' : région 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 déjà un département '||v_dept||
' pour la région '||'&p_nom_region';
WHEN e_count THEN
ROLLBACK;
:g_mess := 'Le département numéro '||TO_CHAR(&p_dept_id)||' n''existe pas.';
END;
/
PRINT g_mess
SQL> start p5q1
Numéro de département : 99
Nom de région : Europe
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Le département numéro 99 n'existe pas
FROM departements
WHERE region_id = v_region_id
AND nom =
(SELECT nom
FROM departements
WHERE id = &p_dept_id);
:g_mess := 'Il existe déjà un département '||v_dept||
' pour la région '||'&p_nom_region';
WHEN e_count THEN
ROLLBACK;
:g_mess := 'Le département numéro '||TO_CHAR(&p_dept_id)||' n''existe pas.';
END;
/
PRINT g_mess
SQL> start p5q1
Numéro de département : 99
Nom de région : Europe
PL/SQL procedure successfully completed.
G_MESS
--------------------------------------------------------------------
Le département numéro 99 n'existe pas
Structure et Données des Tables
SQL>desc departements
SQL>SELECT * FROM departements
SQL>desc Commandes
SQL>desc employes
SQL>SELECT * FROM employes
Article plus récent Article plus ancien