Vous êtes sur la page 1sur 32

A

Mostafa Hanoune

Solutions des exercices

Solutions Exercice 1 1. Evaluez chacune des dclarations suivantes. Dterminez lesquelles sont invalides et expliquez pourquoi. a. DECLARE v_id NUMBER(4);

Valide b. DECLARE v_x, v_y, v_z

VARCHAR2(10);

Invalide car un seul identifiant est autoris par ligne de dclaration c. DECLARE v_birthdate

DATE NOT NULL;

Invalide car une variable NOT NULL doit tre initialise sa cration

d.

DECLARE v_in_stock

BOOLEAN := 1;

Invalide, 1 nest pas une expression Boolenne

Les Bases PL/SQL A-2

Solutions Exercice 1 (suite) 2. Dans chacunes des affectations suivantes, dterminez le type de lexpression rsultante.. a. v_days_to_go Number b. v_sender Character c. v_sum := $100,000 + $250,000; := USER || ': ' || TO_CHAR(v_dept_no); := v_due_date - SYSDATE;

Invalide; le PL/SQL ne peut convertir des symboles spciaux de VARCHAR2 vers NUMBER d. v_flag Boolean e. v_n1 Boolean f. v_value := NULL; := v_n2 > (2 * v_n3); := TRUE;

Tout type scalaire de donne 3. Crez un bloc anonyme qui affiche lcran la phrase Mon bloc PL/SQL fonctionne. . VARIABLE g_message VARCHAR2(30) BEGIN :g_message := 'Mon Bloc PL / SQL fonctionne'; END; / PRINT g_message SQL> START p1q3.sql

G_MESSAGE -----------------------------------------------------Mon bloc PL/SQL fonctionne

Les Bases PL/SQL A-3

Solutions Exercice 1 (suite) Si vous avez le temps, faites lexercice suivant : 4. Crez un bloc qui dclare deux variables. Affectez la valeur de ces variables PL/SQL des variables htes SQL*Plus et affichez les rsultats des variables PL/SQL lcran. Excutez votre bloc PL/SQL. Enregistrez votre bloc PL/SQL dans un fichier nomm plq4.sql. V_CHAR Character (variable length) V_NUM Number Affecter ces variables les valeurs suivantes : Variable V_CHAR V_NUM Valeur La constante :42 est la rponse Les deux premiers caractres de V_CHAR

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

VARIABLE g_char VARCHAR2(30) VARIABLE g_num NUMBER DECLARE v_char VARCHAR2(30); v_num NUMBER(11,2); BEGIN v_char := '42 est la rponse'; v_num := TO_NUMBER(SUBSTR(v_char,1,2)); :g_char := v_char; :g_num := v_num; END; / PRINT g_char PRINT g_num SQL> START p1q4.sql

Les Bases PL/SQL A-4

Solutions Exercice 2 Bloc PL/SQL DECLARE v_weight BEGIN /*SOUS-BLOC*/ DECLARE v_weight v_message BEGIN v_weight := v_weight + 1; v_new_locn := 'Western ' || v_new_locn; END; v_weight := v_weight + 1; v_message := v_message || ' is in stock'; v_new_locn := 'Western ' || v_new_locn; END; NUMBER(3) := 1; VARCHAR2(255) := 'Product 11001'; NUMBER(3) := 600; v_message VARCHAR2(255) := 'Product 10012';

v_new_locn VARCHAR2(50) := 'Europe';

Les Bases PL/SQL A-5

Solutions Exercice 2 (suite) 1. Considrez le bloc PL/SQL ci-dessus et dterminez le type de donnes et la valeur de chacune des variables suivantes daprs les rgles de visibilit a. La valeur de V_WEIGHT dans le sous-bloc est: 2 et le type de donne est NUMBER. b. La valeur de V_NEW_LOCN dans le sous-bloc est : Western Europe et le type de donne est VARCHAR2. c. La valeur de V_WEIGHT dans le bloc principal est : 601 et le type de donne est NUMBER. d. La valeur de V_MESSAGE dans le bloc principal est : Product 10012 is in stock et le type de donne est VARCHAR2. e. La valeur de V_NEW_LOCN dans le bloc principal est : Invalide car v_new_locn n est pas visible en dehors du sous-bloc.

Les Bases PL/SQL A-6

Solutions Exercice 2 (suite) Exemple sur la porte des donnes

DECLARE v_customer BEGIN DECLARE v_customer v_name BEGIN v_customer END; v_customer END; v_name v_credit_rating v_name v_credit_rating NUMBER(7) := 201; VARCHAR2(25) := 'Unisports'; VARCHAR2(50) := 'Womansport'; v_credit_rating VARCHAR2(50) := 'EXCELLENT';

Les Bases PL/SQL A-7

Solutions Exercice 2 (suite) 2. Supposons que vous imbriquiez un sous-bloc dans un bloc, comme ci-dessus. Vous dclarez deux variables, V_CUSTOMER et V_CREDIT_RATING, dans le bloc principal. Vous dclarez aussi deux variables, V_CUSTOMER et V_NAME, dans le sous-bloc. Dterminez les valeurs et le type de de donnes pour chacun des cas suivants. a. La valeur de V_CUSTOMER dans le sous-bloc est: 201 et le type de donne est NUMBER. b. La valeur de V_NAME dans le sous-bloc est : Unisports et le type de donne est VARCHAR2. c. La valeur de V_CREDIT_RATING dans le sous-bloc est : EXCELLENT et le type de donne est VARCHAR2. d. La valeur de V_CUSTOMER dans le bloc principal est: Womansport et le type de donne est VARCHAR2. e. La valeur de V_NAME dans le bloc principal est : V_NAME nest pas visible dans le bloc principal et vous obtenez une erreur. f. La valeur de V_CREDIT_RATING dans le bloc principal est : EXCELLENT et le type de donne est VARCHAR2.

Les Bases PL/SQL A-8

Solutions Exercice 2 (suite) 3. Crez et excutez un bloc PL/SQL qui prenne en compte deux nombres grce des variables de substitution SQL*Plus. Il faut diviser le premier nombre par le second, et ajouter le rsultat au second nombre. Le rsultat doit tre stock dans une variable PL/SQL et affich lcran. SET VERIFY OFF VARIABLE g_result NUMBER ACCEPT p_num1 PROMPT ' Veuillez saisir le premier nombre : ' ACCEPT p_num2 PROMPT ' Veuillez saisir le second nombre : ' DECLARE v_num1 NUMBER(9,2) := &p_num1; v_num2 NUMBER(9,2) := &p_num2; BEGIN :g_result := (v_num1/v_num2) + v_num2; END; / PRINT g_result SET VERIFY ON SQL> START p2q3.sql

ACCEPT p_num1 PROMPT ' Veuillez saisir le premier nombre : ' ACCEPT p_num2 PROMPT ' Veuillez saisir le second nombre : ' DECLARE v_num1 NUMBER(9,2) := &p_num1; v_num2 NUMBER(9,2) := &p_num2; BEGIN dbms_output.put_line(TO_CHAR(v_num1/v_num2) + v_num2); END; /

Les Bases PL/SQL A-9

Solutions Exercice 2 (suite) 4. Codez un bloc PL/SQL qui calcule le gain total pour une anne. Le salaire annuel et le pourcentage de bonus de lanne sont transmis au bloc PL/SQL laide de variables de substitution SQL*Plus, et le bonus doit tre converti dun nombre entier en dcimal (par exemple, 15 en 0,15). Si le salaire est NULL, dfinissez-le zro avant de calculer le traitement total. Excutez le bloc PL/SQL. Rappel : Utilisez la fonction NVL pour manipuler les valeurs NULL. Remarque : Pour tester la fonction NVL, tapez NULL au prompt ; puis [Return] cela provoque une erreur SET VERIFY OFF VARIABLE g_total NUMBER ACCEPT p_salary PROMPT'Veuillez saisir le salaire annuel : ' ACCEPT p_bonus PROMPT 'Veuillez saisir le % de bonus : ' DECLARE v_salary NUMBER := &p_salary; v_bonus NUMBER := &p_bonus; BEGIN :g_total := NVL(v_salary, 0) * (1 + NVL(v_bonus, 0)/ 100); END; / PRINT g_total SET VERIFY ON SQL> START p2q4.sql

ACCEPT p_salary PROMPT'Veuillez saisir le salaire annuel : ' ACCEPT p_bonus PROMPT 'Veuillez saisir le % de bonus : : ' DECLARE v_salary NUMBER := &p_salary; v_bonus NUMBER := &p_bonus; BEGIN dbms_output.put_line(TO_CHAR(NVL(v_salary, 0) * (1 + NVL(v_bonus, 0) / 100))); END; /

Les Bases PL/SQL A-10

Solutions Exercice 3 1. Crez un bloc PL/SQL qui slectionne le plus grand numro de dpartement (DEPTNO) de la table DEPT et le stocke dans une variable SQL*Plus. Affichez le rsultat lcran. Enregistrez votre bloc PL/SQL dans le fichier p3q1.sql. VARIABLE g_max_deptno NUMBER DECLARE v_max_deptno NUMBER; BEGIN SELECT MAX(deptno) INTO v_max_deptno FROM dept; :g_max_deptno := v_max_deptno; END; / PRINT g_max_deptno SQL> START p3q1.sql DECLARE v_max_deptno NUMBER; BEGIN SELECT MAX(deptno) INTO v_max_deptno FROM dept; dbms_output.put_line(TO_CHAR(v_max_deptno)); END; /

2. Modifiez le bloc PL/SQL que vous avez cr la question 1 pour insrer un nouveau dpartement dans la table DEPT. Enregistrez votre bloc PL/SQL dans le fichier p3q2.sql. a. Plutt que dafficher le numro de dpartement extrait dans la question 1, ajoutez 10 ce numro et utilisez ce nouveau numro pour crer le nouveau dpartement. b. Utilisez un paramtre de substitution SQL*Plus pour le nom du dpartement. c. Laissez la localit(LOC) la valeur NULL pour linstant. .

Les Bases PL/SQL A-11

Solutions Exercice 3 (suite) SET VERIFY OFF ACCEPT p_dept_name PROMPT'Veuillez saisir le nom du dpartement:' DECLARE v_max_deptno dept.deptno%TYPE; BEGIN SELECT MAX(deptno)+10 INTO v_max_deptno FROM dept; INSERT INTO dept (deptno, dname, loc) VALUES (v_max_deptno, '&p_dept_name', NULL); COMMIT; END; / SET VERIFY ON d. Excutez le bloc PL/SQL. SQL> START p3q2.sql e. Affichez le nouveau dpartement que vous avez cr. SELECT * FROM dept WHERE deptno = :g_max_deptno + 10; 3. Crez un bloc PL/SQL qui mette jour la localit (LOC) dun dpartement existant. Enregistrez votre bloc PL/SQL dans le fichier p3q3.sql. a. Utilisez un paramtre de substitution SQL*Plus pour le numro du dpartement (DEPTNO). b. Utilisez un paramtre de substitution SQL*Plus pour la localit du dpartement (LOC). c. Testez le bloc PL/SQL d. Affichez le numro, le nom et la localit du dpartement mis jour. SET VERIFY OFF ACCEPT p_deptno PROMPT 'Veuillez saisir le numro dpartement: ' ACCEPT p_loc PROMPT'Veuillez saisir la localit du dpartement:' BEGIN UPDATE dept SET loc = '&p_loc' WHERE deptno = &p_deptno; COMMIT; END; / SET VERIFY ON SQL> START p3q3.sql

Les Bases PL/SQL A-12

Solutions Exercice 3 (suite) e. Affichez le dpartement que vous avez mis jour. SQL> SELECT* 2 FROM dept 3 WHERE deptno = &p_deptno; 4. Crez un bloc PL/SQL qui supprime le dpartement cr la question 2. Enregistrez votre bloc PL/SQL dans le fichier p3q4.sql. a. Utilisez un paramtre de substitution SQL*Plus pour le numro de dpartement. b. Affichez lcran le nombre denregistrements affects. c. Testez le bloc PL/SQL SET VERIFY OFF VARIABLE g_result VARCHAR2(40) ACCEPT p_deptno PROMPT'Veuillez saisir le numro du dpartement:' DECLARE v_result NUMBER(2); BEGIN DELETE FROM dept WHERE deptno = &p_deptno; v_result := SQL%ROWCOUNT; :g_result := (TO_CHAR(v_result) ||enregistrement(s)supprim(s).'); COMMIT; END; / SET VERIFY ON PRINT g_result SQL> START p3q4.sql ACCEPT p_deptno PROMPT 'Veuillez saisir le numro du dpartement:' DECLARE v_result NUMBER(2); BEGIN DELETE FROM dept WHERE deptno = &p_deptno; v_result := SQL%ROWCOUNT; dbms_output.put_line(TO_CHAR(v_result)|| enregistrement(s)supprim(s).'); COMMIT; END; /

Les Bases PL/SQL A-13

Solutions Exercice 3 (suite) d. Que se passe-t-il si vous entrez un numro de dpartement inexistant ? Si loprateur entre un numro de dpartement qui nexiste pas, le bloc PL/SQL termine avec succs parce que cela ne constitue pas une exception. e. Vrifiez que le dpartement a bien t supprim

SQL> SELECT * 2 FROM dept 3 WHERE deptno = 50;

Les Bases PL/SQL A-14

Solutions Exercice 4 1. Excutez le script lab4_1.sql pour crer une table MESSAGES. Ecrivez un Bloc PL/SQL pour insrer des nombres dans la table MESSAGES.. CREATE TABLE messages (results VARCHAR2 (60)) / a. b. Insrez les nombres de 1 10, en excluant 6 et 8. Programmer un commit avant la fin du bloc PL/SQL

BEGIN FOR i IN 1..10 LOOP IF i = 6 or i = 8 THEN null; ELSE INSERT INTO messages(results) VALUES (i); END IF; COMMIT; END LOOP; END; / c. Afficher le contenu de la table MESSAGES pour tester votre bloc PL/SQL SQL> SELECT * 2 FROM messages;

2. Crez un bloc PL/SQL qui calcul le montant de la commission dun employ donn, en fonction de son salaire. a. Executez le script lab4_2.sql qui cre un nouvel employ dans la table EMP. Note : Lemploy aura un salaire NULL. SQL> START lab4_2.sql b. Faites saisir le numro demploy lutilisateur, laide dune variable de substitution SQL*Plus. c. Si le salaire de lemploy est infrieur $1000, la commission vaut 10% du salaire. d. Si le salaire de lemploy est compris entre $1000 et $1500, la commission vaut 15% du salaire. e. Si le salaire de lemploy est suprieur $1500, la commission vaut 20% du salaire. f. Si le salaire de lemploy est NULL, la commission vaut 0. g. Programmer un commit avant la fin du bloc PL/SQL

Les Bases PL/SQL A-15

Solutions Exercice 4 (suite) ACCEPT p_empno PROMPT 'Saisir le numro de lemploy: ' DECLARE v_empno emp.empno%TYPE := &p_empno; v_sal emp.sal%TYPE; v_comm emp.comm%TYPE; BEGIN SELECT sal INTO v_sal FROM emp WHERE empno = v_empno; IF v_sal < 1000 THEN v_comm := .10; ELSIF v_sal BETWEEN 1000 and 1500 THEN v_comm := .15; ELSIF v_sal > 1500 THEN v_comm := .20; ELSE v_comm := 0; END IF; UPDATE emp SET comm = NVL(sal,0) * v_comm WHERE empno = v_empno; COMMIT; END; / h. Excuter votre programme PL/SQL, utiliser le tableau suivant pour tester chaque cas, et vrifier la valeur de la commission

Numro de lemploy 7369 7934 7499 8000

Salaire 800 1300 1600 NULL

Commission obtenue 80 195 320 0

Les Bases PL/SQL A-16

Solutions Exercice 4 (suite) SQL> 2 3 4 SELECT FROM WHERE ORDER BY empno, sal, comm emp empno IN (7369, 7934,7499, 8000) comm;

Sil vous reste du temps, faites les exercices suivants : 3. Modifiez le fichier p1q4.sql pour insrez le texte Nombre pair ou Nombre impair , selon que le nombre correspondant dans la table MESSAGES est pair ou impair. Regardez votre table MESSAGES pour vrifier que le programme PL/SQL a fonctionn. DECLARE v_char VARCHAR2(30); v_num NUMBER(11,2); BEGIN v_char := '42 est la rponse'; v_num := TO_NUMBER(SUBSTR(v_char,1,2)); IF mod(v_num, 2) = 0 THEN INSERT INTO messages (results) VALUES ('Nombre pair'); ELSE INSERT INTO messages (results) VALUES ('Nombre impair'); END IF; END; / SQL> SELECT * 2 FROM messages; 4. Ajoutez une nouvelle colonne STARS varchar2(100), dans la table EMP qui permettra de stocker des toiles (*). SQL> ALTER TABLE emp 2 ADD stars VARCHAR2(100); 5. Crez un programme PL/SQL qui rcompense les employs en leur attribuant une toile dans la colonne STARS par tranche de salaire de $100.Sauvegardez votre programme PL/SQL sous le nom p4q5.sql. a. Faites saisir le numro demploy lutilisateur, par une variable de substitution SQL*Plus. b. Initialiser une variable qui contiendra un ensemble dtoile (*). c. Ajoutez une toile la chane par tranche de salaire de $100. Par exemple , si lemploy a un salaire de $800, la chane comportera 8 toiles. Si lemploy touche un salaire de $1250, la chane comportera 13 toiles. d. Programmer un Update de la colonne STARS de tous les employs avec cette chane (*);

Les Bases PL/SQL A-17

Solutions Exercice 4 (suite) e. Programmer un commit avant la fin du bloc PL/SQL f. Testez le programme pour les employs qui nont pas de salaires et pour ceux qui en ont un.

SET VERIFY OFF ACCEPT p_empno PROMPT ' Entrez le numro demploy : ' DECLARE v_empno emp.empno%TYPE := &p_empno; v_asterisk emp.stars%TYPE := NULL; v_sal emp.sal%TYPE; BEGIN SELECT NVL(ROUND(sal/100), 0) INTO v_sal FROM emp WHERE empno = v_empno; FOR i IN 1..v_sal LOOP v_asterisk := v_asterisk ||'*'; END LOOP; UPDATE emp SET stars = v_asterisk WHERE empno = v_empno; COMMIT; END; / SET VERIFY ON SQL> START p4q5.sql SQL> SELECTempno, sal, stars 2 FROM emp 3 WHERE empno IN (7934, 8000);

Les Bases PL/SQL A-18

Solutions Exercice 5 1. Crez un bloc PL/SQL pour retrouver le nom de chaque dpartement partir de la table DEPT et affichez le nom de chaque dpartement lcran, en utilisant une table PL/SQL. a. Dclarez une table PL/SQL, MY_DEPT_TABLE, pour stocker temporairement le nom de ces dpartements. b. En utilisant une boucle, retrouvez le nom de tous les dpartements de la table DEPT et stockezles dans la TABLE PL/SQL. Chaque dpartement a un numro multiple de 10. c. En utilisant une autre boucle, retrouvez les noms des dpartements dans la TABLE PL/SQL et affichez-les lcran en utilisant DBMS_OUTPUT.PUT_LINE. SET SERVEROUTPUT ON DECLARE TYPE dept_table_type is table of dept.dname%TYPE INDEX BY BINARY_INTEGER; my_dept_table dept_table_type; v_count NUMBER (2); BEGIN SELECT COUNT(*) INTO v_count FROM dept; FOR i IN 1..v_count LOOP SELECT dname INTO my_dept_table(i) FROM dept WHERE deptno = i*10; END LOOP; FOR i IN 1..v_count LOOP DBMS_OUTPUT.PUT_LINE (my_dept_table(i)); END LOOP; END; /

2. Ecrivez un bloc PL/SQL permettant dafficher des informations dune commande donne. a. Dclarez un record PL/SQL bas sur la structure de la table ORD. b. Utilisez une variable de substitution SQL*Plus pour retrouver les informations relatives une commande spcifique et stockez cette information dans le record PL/SQL. c. Utilisez DBMS_OUTPUT. PUT_LINE pour afficher les informations de cette commande.

Les Bases PL/SQL A-19

Solutions Exercice 5 (suite)

SET SERVEROUTPUT ON SET VERIFY OFF ACCEPT p_ordid PROMPT ' Entrer un numro de commande : ' DECLARE ord_record ord%ROWTYPE; BEGIN SELECT * INTO ord_record FROM ord WHERE ordid = &p_ordid; DBMS_OUTPUT.PUT_LINE ('La commande '|| TO_CHAR(ord_record.ordid)|| ' a t saisie le ' || TO_CHAR(ord_record.orderdate) || ' et livre le ' || TO_CHAR(ord_record.shipdate) || ' pour un total de ' || TO_CHAR(ord_record.total,'$99,999.99')); END; / Sil vous reste du temps. 3. Modifiez le bloc PL/SQL que vous avez cr dans lexercice 1, pour retrouvez toutes les informations relatives chaque dpartement de DEPT et affichez ces informations lcran en utilisant une Table de Records PL/SQL. a. Dclarez une table PL/SQL, MY_DEPT_TABLE, pour stocker temporairement les numro, nom, et location de chaque dpartement. b. En utilisant une boucle, retrouvez les informations pour chaque dpartement situ dans la table DEPT, et stockez-les dans la table PL/SQL. Chaque dpartement a un numro multiple de 10. c. En utilisant une autre boucle, retrouvez les informations relatives aux dpartements, stockez-les dans la table PL/SQL et affichez-les lcran en utilisant DBMS_OUTPUT.PUT_LINE.

Les Bases PL/SQL A-20

Solutions Exercice 5 (suite) SET SERVEROUTPUT ON DECLARE TYPE dept_table_type is table of dept%ROWTYPE INDEX BY BINARY_INTEGER; my_dept_table dept_table_type; v_count NUMBER (2); BEGIN SELECT COUNT(*) INTO v_count FROM dept; FOR i IN 1..v_count LOOP SELECT * INTO my_dept_table(i) FROM dept WHERE deptno = i*10; END LOOP; FOR i IN 1..v_count LOOP DBMS_OUTPUT.PUT_LINE ('Dept. ' || my_dept_table(i).deptno || ',' || my_dept_table(i).dname || ' est situ ' || my_dept_table(i).loc); END LOOP; END; /

Les Bases PL/SQL A-21

Solutions Exercice 6 1. Lancez le script lab6_1.sql pour crer une table afin dy stocker les employs et leur salaire. SQL> CREATE TABLE top_dogs 2 (name VARCHAR2(25), 3 salary NUMBER(11,2)); 2. Crer un bloc PL/SQL qui dtermine les employs ayant les salaires les plus levs. a. Faire saisir lutilisateur une valeur n dans un paramtre de substitution SQL*PLUS. b. Dans une boucle, rcuprez les noms et salaires des personnes les mieux rmunres dans la table EMP. c. Enregistrez les noms et salaires dans la table TOP_DOGS. d. Assurez-vous que deux employs naient pas le mme salaire. e. Testez les cas particuliers tels que n = 0 et n >au nombre total demploys dans EMP. Afficher le contenu de la table TOP_DOGS lcran aprs chaque test et prvoir de videz ensuite cette table.

Les Bases PL/SQL A-22

Solutions Exercice 6 (suite)

DELETE FROM top_dogs; ACCEPT p_num PROMPT ' Entrez le nombre des employs les mieux rmunrs:' DECLARE v_num NUMBER(3) := &p_num; v_ename emp.ename%TYPE; v_sal emp.sal%TYPE; CURSOR emp_cursor IS SELECT ename, sal FROM emp WHERE sal IS NOT NULL ORDER BY sal DESC; BEGIN OPEN emp_cursor; FETCH emp_cursor INTO v_ename, v_sal; WHILE emp_cursor%ROWCOUNT <= v_num AND emp_cursor%FOUND LOOP INSERT INTO top_dogs (name, salary) VALUES (v_ename, v_sal); FETCH emp_cursor INTO v_ename, v_sal; END LOOP; CLOSE emp_cursor; COMMIT; END; / SELECT * FROM top_dogs;

Les Bases PL/SQL A-23

Solutions Exercice 6 (suite) 3. Considrez le cas o plusieurs employs ont le mme salaire. Si une personne est liste, alors toutes les personnes ayant le mme salaire devraient ltre aussi. a. Par exemple, si lutilisateur saisi la valeur 2 : alors King, Ford, et Scott devraient tre affichs. (Ces employs ont le second plus haut salaire). b. Si lutilisateur saisi la valeur 3 : alors King, Ford, Scott, et Jones devraient tre affichs. c. Videz toutes les lignes de TOP_DOGS et entranez-vous. TRUNCATE TABLE top_dogs; ACCEPT p_num PROMPT ' Entrez le nombre des employs les mieux rmunrs : ' DECLARE v_num NUMBER(3) := &p_num; v_ename emp.ename%TYPE; v_current_sal emp.sal%TYPE; v_last_sal emp.sal%TYPE; CURSOR emp_cursor IS SELECT ename, sal FROM emp WHERE sal IS NOT NULL ORDER BY sal DESC; BEGIN OPEN emp_cursor; FETCH emp_cursor INTO v_ename, v_current_sal; WHILE emp_cursor%ROWCOUNT <= v_num AND emp_cursor%FOUND LOOP INSERT INTO top_dogs (name, salary) VALUES (v_ename, v_current_sal); v_last_sal := v_current_sal; FETCH emp_cursor INTO v_ename, v_current_sal; IF v_last_sal = v_current_sal THEN v_num := v_num + 1; END IF; END LOOP; CLOSE emp_cursor; COMMIT; END; / SELECT * FROM top_dogs;

Les Bases PL/SQL A-24

Solutions Exercice 7 1. Ecrivez une requte pour obtenir tous les dpartements ainsi que leurs employs. Insrez le rsultat dans la table MESSAGES. Utilisez un curseur pour obtenir le numro de dpartement et passez ce numro un curseur pour obtenir les employs de ce dpartement.

DECLARE v_current_deptno dept.deptno%TYPE; v_emp VARCHAR2(50); CURSOR dept_cursor IS SELECT deptno FROM dept ORDER BY deptno; CURSOR emp_cursor(v_deptno NUMBER) IS SELECT ename ||' - Department '||TO_CHAR(deptno) FROM emp WHERE deptno = v_deptno; BEGIN OPEN dept_cursor; LOOP FETCH dept_cursor INTO v_current_deptno; EXIT WHEN dept_cursor%NOTFOUND; IF emp_cursor%ISOPEN THEN CLOSE emp_cursor; END IF; OPEN emp_cursor (v_current_deptno); LOOP FETCH emp_cursor INTO v_emp; EXIT WHEN emp_cursor%NOTFOUND; INSERT INTO messages (results) VALUES (v_emp); END LOOP; CLOSE emp_cursor; END LOOP; CLOSE dept_cursor; COMMIT; END; / SQL> START p7q1.sql SQL> SELECT * 2 FROM messages;

Les Bases PL/SQL A-25

Solutions Exercice 7 (suite) 2. Modifiez p4q5.sql pour incorporer les fonctionnalits de FOR UPDATE et de WHERE CURRENT OF dans le traitement du curseur. SET VERIFY OFF ACCEPT p_empno PROMPT 'Entrez le numro demploy : ' DECLARE v_empno emp.empno%TYPE := &p_empno; v_asterisk emp.stars%TYPE := NULL; CURSOR emp_cursor IS SELECT empno, NVL(ROUND(sal/100), 0) sal FROM emp WHERE empno = v_empno FOR UPDATE; BEGIN FOR emp_record IN emp_cursor LOOP FOR i IN 1..emp_record.sal LOOP v_asterisk := v_asterisk ||'*'; END LOOP; UPDATE emp SET stars = v_asterisk WHERE CURRENT OF emp_cursor; v_asterisk := NULL; END LOOP; COMMIT; END; / SET VERIFY ON SQL> START p7q2.sql SQL> SELECT empno, sal, stars 2 FROM emp 3 WHERE empno IN (7844, 7900, 8000);

Les Bases PL/SQL A-26

Solutions Exercice 8 1. Ecrire un bloc PL/SQL permettant de slectionner le nom dun employ en connaissant le montant de son salaire. a. Si le salaire entr, renvoie plus dune ligne, traiter lexception avec une fonction approprie et insrer dans la table MESSAGES le message suivant : Plus dun employ le salaire : <salaire>. b. Si le salaire entr ne renvoie aucune ligne, traiter lexception avec une fonction approprie et insrer dans la table MESSAGES le message suivant : Pas demploy avec ce salaire : <salaire>. c. Si le salaire entr ne renvoie quune ligne, insrer dans la table MESSAGES le nom de lemploy et le montant de son salaire. d. Traiter toute autre exception avec une fonction approprie et insrer dans la table MESSAGES le message Autre erreur. e. Tester le programme. SET VERIFY OFF ACCEPT p_sal PROMPT 'Entrez le montant du salaire : ' DECLARE v_ename emp.ename%TYPE; v_sal emp.sal%TYPE := &p_sal; BEGIN SELECT ename INTO v_ename FROM emp WHERE sal = v_sal; INSERT INTO messages (results) VALUES (v_ename || ' - ' || v_sal); EXCEPTION WHEN no_data_found THEN INSERT INTO messages (results) VALUES ('Aucun employ avec un salaire de'|| TO_CHAR(v_sal)); WHEN too_many_rows THEN INSERT INTO messages (results) VALUES ('Plus dun employ avec un salaire de '|| TO_CHAR(v_sal)); WHEN others THEN INSERT INTO messages (results) VALUES ('Une autre erreur est survenue.'); END; / SET VERIFY ON SQL> START p8q1.sql SQL> START p8q1.sql SQL> START p8q1.sql avec

Les Bases PL/SQL A-27

Solutions Exercice 8 (suite) 2. Modifier p3q3.sql pour ajouter une fonction de traitement des exceptions. a. Ecrire une fonction de traitement des exceptions pour transmettre un message lutilisateur indiquant que le dpartement nexiste pas. b. Excuter le programme PL/SQL en entrant un dpartement qui nexiste pas. SET VERIFY OFF VARIABLE g_message VARCHAR2(40) ACCEPT p_deptno PROMPT ' Entrer le numro de dpartement : ' ACCEPT p_loc PROMPT ' Entrer la localit du dpartement : ' DECLARE e_invalid_dept EXCEPTION; v_deptno dept.deptno%TYPE := &p_deptno; BEGIN UPDATE dept SET loc = '&p_loc' WHERE deptno = v_deptno; IF SQL%NOTFOUND THEN raise e_invalid_dept; END IF; COMMIT; EXCEPTION WHEN e_invalid_dept THEN :g_message := 'Le Dpartement '|| TO_CHAR(v_deptno) || ' nexiste pas'; END; / SET VERIFY ON PRINT g_message SQL> START p8q2.sql

Les Bases PL/SQL A-28

Solutions Exercice 8 (suite) SET VERIFY OFF ACCEPT p_deptno PROMPT ' Entrer le numro de dpartement : ' ACCEPT p_loc PROMPT ' Entrer la localit du dpartement : ' DECLARE e_invalid_dept EXCEPTION; v_deptno dept.deptno%TYPE := &p_deptno; BEGIN UPDATE dept SET loc = '&p_loc' WHERE deptno = v_deptno; IF SQL%NOTFOUND THEN raise e_invalid_dept; END IF; COMMIT; EXCEPTION WHEN e_invalid_dept THEN dbms_output.put_line(' Le Dpartement '|| TO_CHAR(v_deptno)|| ' nexiste pas '); END; / SET VERIFY ON

Les Bases PL/SQL A-29

Solutions Exercice 8 (suite) 3. Ecrire un programme PL/SQL qui affiche le nombre demploys qui gagnent 100 $ de plus ou de moins que le montant du salaire donn. a. Sil ny a pas demploys dans cette tranche de salaires, afficher un message lutilisateur en utilisant une exception. b. Sil y a au moins un employ dans cette tranche de salaires, le message doit indiquer combien demploys sont dans cette tranche. c. Traiter toute autre exception avec une fonction approprie. Le message doit indiquer quune autre erreur est survenue. VARIABLE g_message VARCHAR2(100) SET VERIFY OFF ACCEPT p_sal PROMPT 'Entrez le salaire : ' DECLARE v_sal emp.sal%TYPE := &p_sal; v_low_sal emp.sal%TYPE := v_sal - 100; v_high_sal emp.sal%TYPE := v_sal + 100; v_no_emp NUMBER(7); e_no_emp_returned EXCEPTION; e_more_than_one_emp EXCEPTION; BEGIN SELECT count(ename) INTO v_no_emp FROM emp WHERE sal between v_low_sal and v_high_sal; IF v_no_emp = 0 THEN RAISE e_no_emp_returned; ELSIF v_no_emp > 0 THEN RAISE e_more_than_one_emp; END IF; EXCEPTION WHEN e_no_emp_returned THEN :g_message := 'Il ny a pas demploy avec un salaire entre '||TO_CHAR(v_low_sal) || ' et '|| TO_CHAR(v_high_sal); WHEN e_more_than_one_emp THEN :g_message := 'Il y a '|| TO_CHAR(v_no_emp) || ' employ(s) avec un salaire entre '|| TO_CHAR(v_low_sal) || ' et '|| TO_CHAR(v_high_sal); END; / SET VERIFY ON PRINT g_message SQL> START p8q3.sql

Les Bases PL/SQL A-30

Solutions Exercice 8 (suite) SET VERIFY OFF ACCEPT p_sal PROMPT 'Entrez le salaire : ' DECLARE v_sal emp.sal%TYPE := &p_sal; v_low_sal emp.sal%TYPE := v_sal - 100; v_high_sal emp.sal%TYPE := v_sal + 100; v_no_emp NUMBER(7); e_no_emp_returned EXCEPTION; e_more_than_one_emp EXCEPTION; BEGIN SELECT count(ename) INTO v_no_emp FROM emp WHERE sal between v_low_sal and v_high_sal; IF v_no_emp = 0 THEN RAISE e_no_emp_returned; ELSIF v_no_emp > 0 THEN RAISE e_more_than_one_emp; END IF; EXCEPTION WHEN e_no_emp_returned THEN dbms_output.put_line('Il ny a pas demploy avec un salaire entre '|| TO_CHAR(v_low_sal) || ' et '|| TO_CHAR(v_high_sal)); WHEN e_more_than_one_emp THEN dbms_output.put_line('Il y a '|| TO_CHAR(v_no_emp) || ' employ(s) avec un salaire entre '|| TO_CHAR(v_low_sal) || ' et '|| TO_CHAR(v_high_sal)); WHEN others THEN dbms_output.put_line( Une autre erreur sest produite.'); END; / SET VERIFY ON

Les Bases PL/SQL A-31

Les Bases PL/SQL A-32