Licence SMI 2007 – 2008

PL/SQL, Programming, Database Management · exam

Licence SMI 2007 – 2008

B.OUAHBI

PL/SQL

NUMBER(4);

VARCHAR2(10);

Exercice 1 :

Parmi les déclarations de variables suivantes, déterminer celles qui sont incorrectes :

A - DECLARE

v_id

Correcte

B - DECLARE

v_x,v_y,v_z

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

Incorrecte : 1 n’est pas une valeur booléenne

E - DECLARE

emp_record

Incorrecte : EMP_RECORD_TYPE doit être déclaré

F - DECLARE

TYPE

INDEX BY BINARY_INTEGER;

dept_table_nom

Correcte

type_table_nom IS TABLE OF VARCHAR2(20)

type_table_nom;

emp_record_type;

BOOLEAN := 1;

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

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

INTO

FROM

WHERE

commandes

vendeur_id = &p_id;

v_somme_total

SUM(total)

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 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 :

l 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).

l Sinon afficher : ‘y lignes ont été modifiées pour la région x’(y étant le nombre de lignes

modifiées).

Annuler les modifications (rollback).

Fichier p3q2.sql.

VARIABLE g_mess VARCHAR2(500)

DECLARE

v_sortie

v_modifies NUMBER(2);

v_solvable VARCHAR2(25);

c_peu

VARCHAR2(500);

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

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);

$2,500

$1,550

$1,525

$1,515

END LOOP;

CLOSE emp_cursor;

Publicité

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

Ropeburn

Nguyen

Sedeghi

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

-------------------------

Velasquez

Ropeburn

Nguyen

Sedeghi

Giljum

SALAIRE

-----------

$2,500

$1,550

$1,525

$1,515

$1,490

Ngao

$1,450

Quick-To-See $1,450

$1,450

Dumas

$1,400

Nagayama

$1,400

Maduro

$1,400

Magee

$1,307

Havel

$1,300

Catchpole

$1,250

Menchu

$1,200

Urguhart

$1,200

Nozaki

$1,100

Biri

$1,100

Schwartz

$940

Smith

$860

Dancs

$850

Markarian

$800

Chang

$795

Patel

$795

Patel

$750

Newman

$750

Newman

$750

Newman

$750

Newman

$750

Newman

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

INTO

FROM

WHERE UPPER(nom)=UPPER('&p_nom_region');

UPDATE

SET region_id=v_region_id

WHERE

:g_mess := 'Le département : '||TO_CHAR(&p_dept_id)||

’ est affecté à la région '||TO_CHAR(v_region_id);

id

v_region_id

regions

id = &p_dept_id;

departements

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

INTO

FROM

WHERE UPPER(nom)=UPPER('&p_nom_region');

UPDATE

SET region_id=v_region_id

WHERE

:g_mess := 'Le département : '||TO_CHAR(&p_dept_id)||

’ est affecté à la région '||TO_CHAR(v_region_id);

id

v_region_id

regions

id = &p_dept_id;

departements

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

*

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 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

v_region_id regions.id%TYPE;

BEGIN

SELECT

INTO

FROM

WHERE UPPER(nom)=UPPER('&p_nom_region');

UPDATE

SET region_id=v_region_id

WHERE

:g_mess := 'Le département : '||TO_CHAR(&p_dept_id)||

’ est affecté à la région '||TO_CHAR(v_region_id);

id

v_region_id

regions

VARCHAR2(20);

id = &p_dept_id;

departements

COMMIT;

EXCEPTION

WHEN NO_DATA_FOUND THEN

ROLLBACK;

:g_mess := '&p_nom_region'||' : région inexistante.';

WHEN DUP_VAL_ON_INDEX THEN

ROLLBACK;

SELECT

INTO

FROM

WHERE

AND nom =

nom||' (N°'||TO_CHAR(id)||')'

v_dept

departements

region_id = v_region_id

(SELECT

FROM

WHERE

nom

departements

id = &p_dept_id);

:g_mess := 'Il existe déjà un département '||v_dept||

Publicité

' pour la région '||'&p_nom_region';

END;

/

PRINT g_mess

e) Suite

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

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

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

v_region_id regions.id%TYPE;

e_count

BEGIN

SELECT

INTO

FROM

WHERE UPPER(nom)=UPPER('&p_nom_region');

UPDATE

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);

id

v_region_id

regions

VARCHAR2(20);

EXCEPTION;

departements

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

FROM

WHERE

AND nom =

v_dept

departements

region_id = v_region_id

(SELECT

FROM

WHERE

nom

departements

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

g) Suite

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

Name

--------------------------------------

ID

NOM

REGION_ID

Null?

----------------

NOT NULL

NOT NULL

Type

--------------------------

NUMBER(7)

VARCHAR2(25)

NUMBER(7)

SQL>SELECT * FROM departements

ID

------

10

31

32

33

34

35

41

42

43

44

45

50

NOM

------------------------------------------

Finance

Ventes

Ventes

Ventes

Ventes

Ventes

Opérations

Opérations

Opérations

Opérations

Opérations

Administration

REGION_ID

-----------------

1

1

2

3

4

5

1

2

3

4

5

1

Null?

---------------

NOT NULL

NOT NULL

SQL>desc Commandes

Name

-----------------------

ID

CLIENT_ID

DATE_COMM

DATE_EXP

VENDEUR_ID

TOTAL

TYPE_PAIEMENT

COMM_REMPLIE

Null?

NOT NULL

NOT NULL

SQL>desc employes

Name

----------------------------- -------------------------

ID

NOM

PRENOM

USERID

DATE_EMB

COMMENTAIRES

RESPONSABLE_ID

POSTE

DEPT_ID

SALAIRE

COMMISSION

Type

-------------------------

NUMBER(7)

NUMBER(7)

DATE

DATE

NUMBER(7)

NUMBER(11,2)

VARCHAR2(8)

VARCHAR2(1)

Type

----------------------------

NUMBER(7)

VARCHAR2(25)

VARCHAR2(25)

VARCHAR2(8)

DATE

VARCHAR2(255)

NUMBER(7)

VARCHAR2(25)

NUMBER(7)

NUMBER(11,2)

NUMBER(4,2)

SQL>SELECT * FROM employes

ID

---

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Publicité

20

21

22

23

24

25

NOM

------------

Velasquez

Ngao

Nagayama

Quick-To-See

Ropeburn

Urguhart

Menchu

Biri

Catchpole

Havel

Magee

Giljum

Sedeghi

Nguyen

Dumas

Maduro

Smith

Nozaki

Patel

Newman

Markarian

Chang

Patel

Dancs

Schwartz

PRENOM USERID

------------ ----------

cvelasqu

Carmen

lngao

LaDoris

mnagayam

Midor

mquickto

Mark

aropebur

Audrey

murguhar

Molly

rmenchu

Roberta

Ben

bbiri

Antoinette acatchpo

mhavel

Marta

cmagee

Colin

hgiljum

Henry

ysedeghi

Yasmin

mnguyen

Mai

adumas

André

emaduro

Elena

gsmith

George

anozaki

Akira

vpatel

Vikram

Chad

cnewman

Alexander amarkari

echang

Eddie

rpatel

Radha

bdancs

Bela

sschwart

Sylvie

DATE_EMB

----------------

03-03-90

08-03-90

17-06-91

07-04-90

04-03-90

18-01-91

14-05-91

07-04-90

09-02-92

27-02-91

14-05-90

18-01-92

18-02-91

22-01-92

09-10-91

07-02-92

08-03-90

02-02-91

06-08-91

21-07-91

26-05-91

30-11-90

17-10-90

17-03-91

09-05-91

C M

-- --

1

1

1

1

2

2

2

2

2

3

3

3

3

3

6

6

7

7

8

8

9

9

10

10

POSTE

------------------

Président

VP, Opérations

VP, Ventes

VP, Finance

VP, Administrat.

Resp. Magasin

Resp. Magasin

Resp. Magasin

Resp. Magasin

Resp. Magasin

Représentant

Représentant

Représentant

Représentant

Représentant

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

Magasinier

DE

----

50

41

31

10

50

41

42

43

44

45

31

32

33

34

35

41

41

42

42

43

43

44

44

45

45

CO

---

10

12.5

10

15

17.5

SAL

------

2500

1450

1400

1450

1550

1200

1250

1100

1300

1307

1400

1490

1515

1525

1450

1400

940

1200

795

750

850

800

795

860

1100