Vous êtes sur la page 1sur 24

TD N°1

2-Maitrise des concepts de base :

a- Exécuter: set serveroutput on pour permettre l'affichage avec la requête


DBMS_OUTPUT.put_line

set serveroutput on;

b Ecrire le bloc PL/SQL qui permet d'inialiser deux variables de type varchar2 qui contiennent
respectivement votre nom et votre prénom et de l'afficher.

set serveroutput on;


Declare
v_nom varchar2(20):= 'ZAMMIT CHATTI';
v_prenom varchar2(10) :='Sami';
BEGIN
dbms_output.put_line('nom:'|| v_nom ||',prenom:'|| v_prenom);
END;

C. Ajouter le bloc PL/SQL, précédent l'affichage du nombre de caractère que contient votre
nom et votre prénom (opérateur length) et de vérifier si votre nom ou votre prénom
contient la lettre 'C' dans la troisième position. Utiliser deux variables pour réaliser ceci.

Declare
v_nom varchar2(20):= 'ZAMMIT CHATTI';
v_prenom varchar2(10) :='Sami';

BEGIN
dbms_output.put_line('taille nom:'||length(v_nom)||',prenom
taille:'||length(v_prenom));
if(v_nom like '--c%') or (v_prenom like '__c%') then
dbms_output.put_line('CONTIENT ');
else
dbms_output.put_line('NE CONTIENT PAS c');
end if;
END;

1
d Ecrire le bloc PL/SQL qui permet de réaliser une boucle qui permet d'afficher 10 premiers
entiers avec 10(utiliser les trois types de boucles, FOR, WHILE et LOOP)

--While--
set serveroutput on;
Declare
v_cpt number(2):= 1;

BEGIN

WHILE v_cpt<=10 LOOP


dbms_output.put_line(v_cpt);
v_cpt:= v_cpt+1;
END LOOP;

END;

--for--
set serveroutput on;
Declare
v_cpt number(2):= 1;

BEGIN
FOR v_cpt in 1..10 LOOP
dbms_output.put_line(v_cpt);
END LOOP;

END;

-- do while--
set serveroutput on;
Declare
v_cpt number(2):= 1;
BEGIN
v_cpt:= 1;

LOOP
dbms_output.put_line(v_cpt);
v_cpt:= v_cpt+1;
EXIT WHEN v_cpt>10;

END LOOP;
END;

2
3—Manipulation basique des tables

A-- Ecrire le bloc PL/SQL qui permet d’afficher les informations de l’employé KRUNAL :

set serveroutput on;


DECLARE
v_nom emp%ROWTYPE;
BEGIN
select * into v_nom from emp where ename='KRUNAL';
dbms_output.put_line(v_nom.eno||' '|| v_nom.ename ||' '|| v_nom.title || ' '||
v_nom.city);
END;

B ecrire le bloc qui permet d'afficher les informations de l'employé qui est de la ville de
TORONTO

Il y a plusieurs employés dans la ville de TORONTO notre variable ne peut supporter qu'une
seule ligne

C Écrire Le bloc PL/SQL qui permet d'afficher les n premiers entiers avec n la taille de la table
emp

set serveroutput on;


Declare
v_cpt number(2):= 1;
v_nb_emp number(2);

BEGIN
select count(*) into v_nb_emp from emp;
WHILE v_cpt<=v_nb_emp LOOP
dbms_output.put_line(v_cpt);
v_cpt:= v_cpt+1;
END LOOP;
END;

3
D Écrire le bloc Pl/SQL qui permet d'afficher les employés de EMP en utilisant leurs
identifiants:

set serveroutput on;


Declare
v_cpt number(2):= 1;
v_nb_emp number(2);
v_info emp%rowtype;

BEGIN
select count(*) into v_nb_emp from emp;
WHILE v_cpt<=v_nb_emp LOOP
select * into v_info from emp where eno='E'||v_cpt;
dbms_output.put_line(v_info.eno||' '||v_info.ename||' '||v_info.title||' '||v_info.city);
v_cpt:= v_cpt+1;
END LOOP;
END;

E Écrire le bloc PL/SQL qui permet d'afficher les durées de travail (table works) paires de
chaque employé sans utiliser where

set serveroutput on;


Declare
v_cpt number(2):= 1;
v_nb_emp number(2);
v_info works%rowtype;

BEGIN
select count(*) into v_nb_emp from works;
WHILE v_cpt<=v_nb_emp LOOP
select * into v_info from works where eno='E'||v_cpt;
if mod(v_info.dur,2)=0 then
dbms_output.put_line(v_info.eno||' '||v_info.pno||' '||v_info.dur);
end if;
v_cpt:= v_cpt+1;
END LOOP;
END;

4
F- Ecrire le bloc PL/SQL qui permet d'insérer 5 employés de E9 à E13 qui sont des
programmeurs à NEW YORK. Les noms sont identiques à leurs identifiants.
(Utilisation d'une boucle)

set SERVEROUTPUT ON;


Declare
v_cpt number(2):=9;
BEGIN
While v_cpt<=13 LOOP
insert into emp values('E'||v_cpt,'E'||v_cpt,'PROGRAMMER','NEW YORK');
v_cpt:=v_cpt+1;
END LOOP;
END;

G. écrire le bloc PL/SQL qui permet de modifier l'emploie des 5 employés de NEW YORK de
PROGRAMMER à Support STAFF.

BEGIN
UPDATE emp
SET title='SUPPORT STAFF' WHERE city='NEW YORK';
END;

5
TD 2
A. Ecrire le bloc PL/SQL qui permet de parcourir et afficher tous les employés avec la boucle FOR (explicite-
curseur à déclarer).

declare
cursor c_emp is
select * from emp;
begin
for v_emp in c_emp loop
dbms_output.put_line('eno :'||v_emp.eno);
dbms_output.put_line('ename :'||v_emp.ename);
dbms_output.put_line('title :'||v_emp.title);
dbms_output.put_line('city :'||v_emp.city);
end loop;
end;

B. Ecrire le bloc PL/SQL qui permet de parcourir et afficher tous les employés avec la boucle WHILE.

declare
cursor c_emp is
select * from emp;
v_emp c_emp%rowtype;
begin

open c_emp;
fetch c_emp into v_emp;

while c_emp%found loop


dbms_output.put_line('eno :'||v_emp.eno);
dbms_output.put_line('ename :'||v_emp.ename);
dbms_output.put_line('title :'||v_emp.title);
dbms_output.put_line('city :'||v_emp.city);
fetch c_emp into v_emp;
end loop;
close c_emp;
end;
C. Ecrire un bloc PL/SQL qui permet d’afficher les employés qui sont des programmeurs tout en utilisant la
boucle FOR paramétrable et afficher le message ‘this employee should REALLY be raised’.
Exemple : Krunal should really be raised.

DECLARE
CURSOR c_emp_to_be_raised(p_title emp.title%TYPE) IS
SELECT * FROM emp WHERE title = p_title;
BEGIN
FOR cRowEmp IN c_emp_to_be_raised('PROGRAMMER') LOOP
dbms_Output.Put_Line(cRowEmp .ename ||' ' ||cRowEmp.title||'... should be raised ;)');
END LOOP;
END;

D. Ecrire le bloc PL/SQL qui permet d’afficher les employés avec leur salaire en utilisant une jointure.

declare
cursor c_emp is
select * from emp join pay using (title);
v_emp c_emp%rowtype;
begin
for v_emp in c_emp loop
dbms_output.put_line('eno :'||v_emp.eno);
dbms_output.put_line('ename :'||v_emp.ename);
dbms_output.put_line('title :'||v_emp.title);
dbms_output.put_line('city :'||v_emp.city);
dbms_output.put_line('salary :'||v_emp.salary);
end loop;
end;

E. EcrireleblocPL/SQL qui permet de modifier les salaires des employés (table PAY) de la manière suivante
o Si le salaire dépasse la moyenne le diminuer par10%
o Sinonl’augmenterpar10%

declare
cursor c_pay is
select * from pay;
average number(10,2);
begin
select avg(SALARY) into average from pay;
dbms_output.put_line('average :'||average);
for vpay in c_pay loop
if (vpay.salary>average) then
update pay set salary=salary*0.9 where title=vpay.title;
else
update pay set salary=salary*1.1 where title=vpay.title;
end if;
end loop;
end;
select * from pay
F. Ecrire le bloc PL/SQL qui permet de calculer la moyenne des salaires pour chaque
ville (avec l’utilisation de group by).

declare
cursor c_emp is
select city,avg(salary) as avg_salary from emp join pay using (title) group by city;

begin
for v_salary in c_emp loop
dbms_output.put_line('salaire de la ville :'||v_salary.city ||' est : '||v_salary.avg_salary);
end loop;
end;

select * from pay;


select * from emp;

g) Ecrire le bloc PL/SQL qui permet de calculer la moyenne des salaires pour chaque
ville (sans l’utilisation de group by).

declare
cursor c_city is
select distinct city from emp;
--cursor c_emp is
-- select * from emp join pay using (title);
average number(10,2);
begin
for v_city in c_city loop
--dbms_output.put_line('salaire de la ville :'||v_city.city );
select avg(salary) into average from emp join pay using (title) where city=v_city.city;
dbms_output.put_line('salaire de la ville :'||v_city.city ||' est : '||average);
end loop;
end;

h) Ecrire le bloc PL/SQL qui permet d’afficher les noms des employés qui travaillent à
LONDON en utilisant FETCH.

DECLARE
CURSOR c_emp IS SELECT eno, ename FROM emp where city='LONDON';
v_id emp.eno%TYPE;
v_nom emp.ename%TYPE;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp into v_id, v_nom;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_id || '' || v_nom);
END LOOP;
CLOSE c_emp;
END;

--------meme exemple curseur paramétrable--------

DECLARE
CURSOR c_emp(ville emp.city%type)
IS SELECT eno, ename FROM emp where city=ville;
v_id emp.eno%TYPE;
v_nom emp.ename%TYPE;
BEGIN
OPEN c_emp('LONDON');
LOOP
FETCH c_emp into v_id, v_nom;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_id || '' || v_nom);
END LOOP;
CLOSE c_emp;
END;
TD 3

a. Écrire une fonction PL/SQL qui permet de retourner le maximum entre deux entiers.

SET SERVEROUTPUT ON;

CREATE OR REPLACE FUNCTION comparaison(nb1 IN NUMBER, nb2 IN NUMBER)


RETURN NUMBER
IS

BEGIN
if nb1>nb2
then return nb1;
else
return nb2;
end if;
END;
/

-- correction du prof
create or replace function maximum_num(val1 in number,val2 in number)
return number
IS
v_nb number;
Begin
v_nb:=0;
IF val1>=val2 THEN
v_nb := val1;
ELSE
v_nb := val2;
END IF;
return v_nb;
End;
/
b. Écrire une fonction qui permet de retourner le nombre d’employés.

CREATE OR REPLACE FUNCTION nombre_emp


RETURN NUMBER
IS
v_nb NUMBER(10);
CURSOR c_nbemp IS SELECT count(*) FROM emp;
BEGIN
OPEN c_nbemp;
FETCH c_nbemp INTO v_nb;
RETURN v_nb;
END;
/
BEGIN
Dbms_output.put_line(nombre_emp());
END;

-- correction du prof
CREATE OR REPLACE FUNCTION nombre_employees
RETURN NUMBER
IS
e_nb NUMBER;
CURSOR c_nb_emp IS SELECT count(*) FROM EMP;
BEGIN
OPEN c_nb_emp;
FETCH c_nb_emp INTO e_nb;
CLOSE c_nb_emp;
RETURN e_nb;
END;
/

C. Écrire une fonction qui permet de retourner le nombre de programmeurs qui travaillent sur un projet Pi.

REATE OR REPLACE FUNCTION nombre_prog(PI in varchar2)


RETURN NUMBER
IS
v_nb NUMBER(10);
CURSOR c_nbprog IS SELECT count(*) FROM emp join works using(eno) where TITLE='PROGRAMMER' and
pno=PI;
BEGIN
OPEN c_nbprog;
FETCH c_nbprog INTO v_nb;
RETURN v_nb;
END;
/
BEGIN
Dbms_output.put_line(nombre_prog('P1'));
END;

-- correction du prof
CREATE OR REPLACE FUNCTION nombre_programmeurs_projet(name_proj in varchar2)
RETURN NUMBER
IS
e_nb NUMBER;
CURSOR c_nb_emp IS select count(*) from emp join works using(ENO) where PNO=name_proj and
TITLE='PROGRAMMER';
BEGIN
OPEN c_nb_emp;
FETCH c_nb_emp INTO e_nb;
CLOSE c_nb_emp;
RETURN e_nb;
END;
/

d. En supposant que le salaire perçu par un employé durant tout un projet est égal le salaire correspondant à son
titre
--multiplié par la durée sur le projet. Écrire une fonction qui permet de déduire l’argent qui doit être ajouté au
budget d’un projet
--donné pour subvenir à la totalité du coût du projet en termes de salaires.

CREATE OR REPLACE FUNCTION budget_cal(PI in varchar2)


RETURN NUMBER
IS
v_budget_projet NUMBER(10);
v_budget_prevu NUMBER(10);
v_diff NUMBER(10);

BEGIN

select sum(salary*dur) into v_budget_projet from works, emp, pay where emp.eno =works.eno
and emp.title=pay.title and pno=PI;
select budget into v_budget_prevu from proj where PNO=PI;
v_diff:= v_budget_prevu-v_budget_projet;
if v_diff<0 then v_diff:=-v_diff;
else v_diff:=0;
end if;
return v_diff;
END;
/

DECLARE
V_COMPL NUMBER(10);
BEGIN

select budget_cal('P1') into V_COMPL from DUAL;


if V_COMPL>0 then Dbms_output.put_line('Il manque: ' ||V_COMPL);
else Dbms_output.put_line('Il ne manque rien');
END IF;
END;

CREATE OR REPLACE FUNCTION budget_to_add(name_proj in varchar2)


RETURN NUMBER
IS
to_ret Number;
BEGIN

select maximum_num(adding,0) INTO to_ret from (


select PNO, sum(SALARIES) - min(budget) as adding from (
select PNO, ENO, TITLE, ENAME, SALARY * DUR as salaries, PNAME, BUDGET from ((EMP JOIN PAY
using(TITLE)) JOIN WORKS using (ENO)) JOIN PROJ USING (PNO) where PNO = name_proj)
group by PNO);

return to_ret;
END;

e. Utiliserla fonction précédemment déclarée pour écrire une procédure PL/SQL qui permet
de rétablir les budgets nécessaires pour chaque projet.

CREATE OR REPLACE PROCEDURE budget_modif


is
CURSOR c_ajout IS SELECT PNO, BUDGET from proj;
v_ajout number;

BEGIN

for x in c_ajout loop


v_ajout:=budget_cal(x.pno);
if v_ajout>0 then update proj set budget=budget + v_ajout/1000 where pno=x.pno;
end if;
end loop;
end;
/
select proj.pno from proj where pno NOT IN
(select proj.pno from emp,works,proj where emp.eno=works.eno and works.pno=proj.pno and
title=upper('MANAGER'));

CREATE OR REPLACE PROCEDURE ajout_manager


is
CURSOR c_ajout IS SELECT PNO, BUDGET from proj;
v_ajout number;

BEGIN

for x in c_ajout loop


v_ajout:=budget_cal(x.pno);
if v_ajout>0 then update proj set budget=budget + v_ajout/1000 where pno=x.pno;
end if;
end loop;
end;
/

-- correction du prof

delete from WORKS;


delete from PROJ;
INSERT INTO PROJ select * from PROJ2;
INSERT INTO WORKS select * from WORKS2;

CREATE OR REPLACE PROCEDURE retablir_budgets(name_proj in varchar2)


IS
budget_old NUMBER;
budget_new NUMBER;
BEGIN
SELECT BUDGET INTO budget_old FROM PROJ where PNO=name_proj;
budget_new := budget_old+budget_to_add(name_proj);
UPDATE proj set BUDGET = budget_new
WHERE PNO = name_proj;

END;
/

CREATE OR REPLACE PROCEDURE retablir_budgets_all_projects


IS
CURSOR c_projs_no IS SELECT PNO FROM PROJ;
BEGIN
for v_proj_no in c_projs_no loop
retablir_budgets(v_proj_no.PNO);
end loop;
END;
/

f. Ecrire
une procédure PL/SQL qui permet d’ajouter un MANAGER sur les projets qui ne
possèdent pas un manager.

CREATE OR REPLACE PROCEDURE ajout_manager


(eno VARCHAR,ename VARCHAR, title VARCHAR,city VARCHAR,laduree NUMBER)
IS
CURSOR c_project IS SELECT DISTINCT proj.pno from proj
where pno NOT IN
(select proj.pno from emp,works,proj where emp.eno=works.eno and works.pno=proj.pno and
title=upper('MANAGER'));

v_num_project VARCHAR(20);
BEGIN
OPEN c_project;
FETCH c_project INTO v_num_project;
INSERT INTO EMP
VALUES(eno,ename,title,city);
INSERT INTO WORKS
VALUES(eno,v_num_project,laduree);
END;

execute ajout_manager('E9','Sami','MANAGER', 'Lyon', 6);

-- correction du prof

CREATE OR REPLACE PROCEDURE add_manager_on_projects


IS
CURSOR c_projs IS select PNO FROM PROJ WHERE PNO NOT IN (
select PNO from works JOIN (select * from EMP where TITLE='MANAGER') USING(ENO)); -- GET THE
PROJECT NOT HAVING A MANAGER;
manager_to_insert EMP%rowtype;

v_dur works.dur%type;

BEGIN
select * into manager_to_insert from EMP where ENO = (select min(ENO) from EMP where TITLE='MANAGER');
--GET A MANAGER IN EMP

for v_proj in c_projs loop


--retablir_budgets(v_proj_no.PNO);
select max(dur) INTO v_dur from works where PNO = v_proj.PNO;
dbms_output.put_line(manager_to_insert.ENO || ',' || v_proj.PNO || ',' || v_dur);
INSERT INTO WORKS VALUES(manager_to_insert.ENO,v_proj.PNO,v_dur);
end loop;
END;
/
TD4

a) Ecrire le bloc PL/SQL qui permet d’afficher les informations de l’employé BUTTERS. Gérer
ensuite l’exception remontée par ce bloc.

set serveroutput on;

DECLARE
v_emp emp%rowtype;
BEGIN
SELECT * into v_emp from emp where upper(ename)='BUTTERS';
DBMS_OUTPUT.PUT_LINE('voici les informations : ' || v_emp.title);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Il n y a pas ce nom');
END;
/

-- correction du prof
declare
v_emp emp%rowtype;
begin
select * into v_emp from emp where ename='BUTTERS';
dbms_output.put_line('eno :'||v_emp.eno);
dbms_output.put_line('ename :'||v_emp.ename);
dbms_output.put_line('title :'||v_emp.title);
dbms_output.put_line('city :'||v_emp.city);
exception
when NO_DATA_FOUND then
dbms_output.put_line('no employee named BUTTERS found !');
end;
/
b) Dans la question 2.b TD1, le bloc PL/SQL remonte une exception puisque la requête select
... into retourne plusieurs valeurs. Modifier la procédure de telle manière à ce que le bloc
affiche le nombre de lignes retournées en utilisant un traitement d’exceptions.
Rappel question 2.b : Ecrire le bloc PL/SQL qui permet d’afficher les informations de
l’employé qui est de la ville ‘TORONTO’. Pourquoi ça ne marche pas ?

DECLARE
v_emp emp%rowtype;
v_excp number;
BEGIN
SELECT * into v_emp from emp where upper(city)='TORONTO';
DBMS_OUTPUT.PUT_LINE('voici les informations : ' || v_emp.title);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Il n y a pas ');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('IL Y A BEAUCOUP DEMPLOYÉS');
select count(*) into v_excp from emp where upper(city)='TORONTO';
DBMS_OUTPUT.PUT_LINE(v_excp);

END;
/

-- correction du prof
declare
v_emp emp%rowtype;
v_count number(10);
begin
select * into v_emp from emp where CITY='Toronto';
dbms_output.put_line('eno :'||v_emp.eno);
dbms_output.put_line('ename :'||v_emp.ename);
dbms_output.put_line('title :'||v_emp.title);
dbms_output.put_line('city :'||v_emp.city);
exception
when TOO_MANY_ROWS then
select count(*) into v_count from emp where CITY='Toronto';
dbms_output.put_line('number of rows is: '|| v_count);
end;
/

c) Ecrire un bloc PL/SQL qui parcours la table des salaires des employés (PAY) en utilisant les
curseurs. Ce bloc doit générer une exception dès qu’il trouve un salaire dépassant le seuil de
10000. L’exception doit être déclarée d’une manière explicite.

DECLARE
cursor c_emp_salaire is (select emp.ename, pay.salary from emp,pay where pay.title=emp.title);
v_emp_salaire c_emp_salaire%rowtype;
emp_riche exception;

BEGIN
open c_emp_salaire;
loop
fetch c_emp_salaire into v_emp_salaire;
exit when c_emp_salaire %NOTFOUND;
if v_emp_salaire.salary > 10000 then
raise emp_riche ;
end if;
end loop;

EXCEPTION
when emp_riche then
dbms_output.put_line('OUI ' || v_emp_salaire.ename || ' GAGNE BCP ');
end;

select distinct emp.eno, count(proj.pno)


from emp, works, proj where emp.eno=works.eno and works.pno=proj.pno group by emp.eno having
count(proj.pno)>0;
-- correction du prof
declare
cursor c_pay is
select SALARY from pay;
SALARY_TOO_HIGH exception;
begin
for v_pay in c_pay loop
if v_pay>10000 then
raise SALARY_TOO_HIGH;
end if;
end loop;
exception
when SALARY_TOO_HIGH then
dbms_output.put_line('too much, too young, too fast !');
end;
/

d) Ecrire un bloc PL/SQL qui permet de générer une exception s’il existe au moins un
employé qui n’est pas affecté a aucun projet.

declare
nb_sans_proj number(10);
emp_sans_proj exception;
begin
select count(*) into nb_sans_proj from (select eno from emp where eno not in(select eno from works));
if nb_sans_proj>0 then
raise emp_sans_proj;
end if;
exception
when emp_sans_proj then
dbms_output.put_line('il existe un employé sans projet');
end;

-- correction du prof
declare
v_count number(10);
EMPLOYEE_WITH_NO_WORK exception;
begin
select count(*) into v_count from
(select distinct eno from emp where eno not in (select eno from works));
if v_count>0 then
raise EMPLOYEE_WITH_NO_WORK;
end if;
exception
when EMPLOYEE_WITH_NO_WORK then
dbms_output.put_line('there is at least one employee without work');
end;
/

Vous aimerez peut-être aussi