Sunteți pe pagina 1din 10

SGBD An III Sem. I Lect. Univ. Dr.

Gabriela Mihai

1
Laborator 1 PL/SQL
Tipuri de date scalare n PL/SQL. Declararea variabilelor. Blocuri. Instruciuni.

PL/SQL include att instruciuni SQL pentru prelucrarea datelor i pentru gestiunea
tranzaciilor, ct i instruciuni proprii.
PL/SQL extinde SQL prin construcii specifice limbajelor procedurale (definirea variabilelor,
declararea tipurilor, utilizarea structurilor de control, implementarea procedurilor i funciilor,
introducerea tipurilor obiect i metodelor etc.).

Tipurile de date scalare
tipurile de date care stocheaz valori numerice
- tipul NUMBER cu subtipurile DEC, DECIMAL, DOUBLE PRECISION, FLOAT,
INTEGER, INT, NUMERIC, REAL, SMALLINT;
- tipul BINARY_INTEGER cu subtipurile NATURAL, NATURALN, POSITIVE,
POSITIVEN, SIGNTYPE;
- tipul PLS_INTEGER.
tipurile de date care stocheaz caractere
- tipul VARCHAR2 cu subtipurile STRING, VARCHAR;
- tipul de date CHAR cu subtipul CHARACTER;
- tipurile LONG, RAW, LONG RAW, ROWID.
tipurile de date care stocheaz data calendaristic i ora
- tipurile DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH
LOCAL TIME ZONE, INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND.
tipurile de date globalizare ce stocheaz date unicode
- tipurile NCHAR i NVARCHAR2.
tipul de date BOOLEAN stocheaz valori logice (true, false sau null).

Declararea variabilelor PL/SQL
Identificatorii PL/SQL trebuie declarai nainte s fie referii n blocul PL/SQL. Dac n
declaraia unei variabile apar referiri la alte variabile, acestea trebuie s fi fost declarate
anterior. Orice variabil declarat ntr-un bloc este accesibil blocurilor coninute sintactic n
acesta.
n declararea variabilelor n PL/SQL pot fi utilizate atributele %TYPE i %ROWTYPE, care
reprezint tipuri de date implicite.
Atributul %TYPE permite definirea unei variabile avnd tipul unei variabile declarate
anterior sau tipul unei coloane dintr-un tabel.
Atributul %ROWTYPE permite definirea unei variabile avnd tipul unei nregistrri dintr-un
tabel.

Sintaxa declarrii unei variabile este urmtoarea:
identificator [CONSTANT]{tip_de_date | identificator%TYPE |
identificator%ROWTYPE} [NOT NULL]
[{:= | DEFAULT} expresie_PL/SQL];

Constantele trebuie iniializate cnd sunt declarate, altfel apare eroare la compilare.
Afiarea valorii variabilelor se face cu ajutorul procedurilor:
DBMS_OUTPUT.PUT(sir_caractere);
DBMS_OUTPUT.PUT_LI NE(sir_caractere);
Obs: se utilizeaz SET SERVEROUTPUT ON pentru activarea modului afiare.



SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

2
Blocuri PL/SQL
PL/SQL este un limbaj cu structur de bloc, adic programele sunt compuse din blocuri care
pot fi complet separate sau ncuibrite unul n altul.
Tipuri de blocuri:
anonime sunt blocuri fr nume, care sunt construite dinamic i sunt executate o singur
dat. Acest tip de bloc nu are argumente i nu returneaz un rezultat;
neanonime sunt fie blocuri avnd un nume (etichetate), care sunt construite static sau
dinamic i sunt executate o singur dat, fie subprograme, pachete sau declanatori.
Un bloc PL/SQL are structura:
[<<nume_bloc>>]
[DECLARE
variabile, cursoare]
BEGIN
instruciuni SQL i PL/SQL
[EXCEPTION
tratarea erorilor]
END[nume_bloc]

Dac blocul PL/SQL este executat fr erori, atunci va apare mesajul:
PL/SQL procedure successfully completed

Instruciuni PL/SQL
PL/SQL dispune de comenzi ce permit controlul execuiei unui bloc. Instruciunile
limbajului pot fi: iterative (LOOP, WHILE, FOR), de atribuire (:=), condiionale (IF, CASE), de salt
(GOTO, EXIT) i instruciunea vid (NULL).

Comentarii n PL/SQL
pe o singur linie, prefixate de simbolurile --, care ncep n orice punct al liniei i se
termin la sfritul acesteia;
pe mai multe linii, care sunt delimitate de simbolurile /* i */.
Caracterul ; este separator pentru instruciuni.

Observaie Pentru a nu se vedea codul PL/SQL la rularea unui script se seteaz parametrul
ECHO la valoare OFF.

1. Evaluai urmtoarele declaraii de variabile:

a. DECLARE
v_nume, v_prenume VARCHAR2(35); -- greit
Corect:
DECLARE
v_nume VARCHAR2(35);
v_prenume VARCHAR2(35);

b. DECLARE
v_nr NUMBER(5); --corect

SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

3
c. DECLARE
v_nr NUMBER(5,2) = 10; --greit
Corect:
DECLARE
v_nr NUMBER(5,2) := 10;

d. DECLARE
v_test BOOLEAN:= SYSDATE; --greit
Corect:
DECLARE
v_test BOOLEAN:=TRUE;

e. DECLARE
v1 NUMBER(5) :=10;
v2 NUMBER(5) :=15;
v3 NUMBER(5) := v1< v2; --greit
Corect:
DECLARE
v1 NUMBER(5) :=10;
v2 NUMBER(5) :=15;
v3 BOOLEAN := v1< v2;
2. Se d urmtorul bloc PL/SQL:
<<principal>>
DECLARE
v_client_id NUMBER(4):= 1600;
v_client_nume VARCHAR2(50):= 'N1';
v_nou_client_id NUMBER(3):= 500;
BEGIN
<<secundar>>
DECLARE
v_client_id NUMBER(4) := 0;
v_client_nume VARCHAR2(50) := 'N2';
v_nou_client_id NUMBER(3) := 300;
v_nou_client_nume VARCHAR2(50) := 'N3';
BEGIN
v_client_id:= v_nou_client_id;
principal.v_client_nume:=
v_client_nume ||' '|| v_nou_client_nume;
--poziia 1
END;
v_client_id:= (v_client_id *12)/10;
--poziia 2
END;
/
Determinai:
- valoarea variabilei v_client_id la poziia 1;
- valoarea variabilei v_client_nume la poziia 1;
- valoarea variabilei v_nou_client_id la poziia 1;
- valoarea variabilei v_nou_client_nume la poziia 1;
- valoarea variabilei v_id_client la poziia 2;
- valoarea variabilei v_client_nume la poziia 2.
SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

4
Soluie:
Poz1 v_client_id 300
Poz1 v_client_nume N2
Poz1 v_nou_client_id 300
Poz1 v_nou_client_nume N3
Poz2 v_client_id 1920
Poz2 v_client_nume N2 N3
3. Creai un bloc anonim care s afieze propoziia "Invat PL/SQL" pe ecran.
Varianta 1 - Afiare folosind variabile de legtur
VARIABLE g_mesaj VARCHAR2(50)
BEGIN
:g_mesaj := 'Invat PL/SQL';
END;
/
PRINT g_mesaj

Varianta 2 - Afiare folosind procedurile din pachetul standard DBMS_OUTPUT
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE('Invat PL/SQL');
END;
/
SET SERVEROUTPUT OFF

4. Definii un bloc anonim n care s se afle numele departamentului cu cei mai muli angajai.
Comentai cazul n care exist cel puin dou departamente cu numr maxim de angajai.

DECLARE
v_dep departments.department_name%TYPE;
BEGIN
SELECT department_name
INTO v_dep
FROM employees e, departments d
WHERE e.department_id=d.department_id
GROUP BY department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employees
GROUP BY department_id);
DBMS_OUTPUT.PUT_LINE('Departamentul '|| v_dep);
END;
/
5. Rezolvai problema anterioar utiliznd variabile de legtur. Afiai rezultatul att din bloc, ct
i din exteriorul acestuia.
VARIABLE rezultat VARCHAR2(35)
BEGIN
SELECT department_name
INTO :rezultat

SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

5
FROM employees e, departments d
WHERE e.department_id=d.department_id
GROUP BY department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employees
GROUP BY department_id);
DBMS_OUTPUT.PUT_LINE('Departamentul '|| :rezultat);
END;
/
PRINT rezultat
6. Modificai exerciiul anterior astfel nct s obinei i numrul de angajai din departamentul
respectiv.
7. Determinai salariul anual i bonusul pe care l primete un salariat al crui cod este dat de la
tastatur. Bonusul este determinat astfel: dac salariul anual este cel puin 20001, atunci bonusul
este 2000; dac salariul anual este cel puin 10001 i cel mult 20000, atunci bonusul este 1000, iar
dac salariul anual este cel mult 10000, atunci bonusul este 500. Afiai bonusul obinut. Comentai
cazul n care nu exist niciun angajat cu codul introdus.
Obs. Se folosete instruciunea I F.

IF condiie1 THEN
secvena_de_comenzi_1
[ELSIF condiie2 THEN
secvena_de_comenzi_2]

[ELSE
secvena_de_comenzi_n]
END IF;

SET VERIFY OFF
DECLARE
v_cod employees.employee_id%TYPE:=&p_cod;
v_bonus NUMBER(8);
v_salariu_anual NUMBER(8);
BEGIN
SELECT salary*12 INTO v_salariu_anual
FROM employees
WHERE employee_id = v_cod;
IF v_salariu_anual>=20001
THEN v_bonus:=2000;
ELSIF v_salariu_anual BETWEEN 10001 AND 20000
THEN v_bonus:=1000;
ELSE v_bonus:=500;
END IF;
DBMS_OUTPUT.PUT_LINE('Bonusul este ' || v_bonus);
END;
/
SET VERIFY ON
8. Rezolvai problema anterioar folosind instruciunea CASE.
CASE test_var
WHEN valoare_1 THEN secvena_de_comenzi_1;
WHEN valoare_2 THEN secvena_de_comenzi_2;
SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

6

WHEN valoare_k THEN secvena_de_comenzi_k;
[ELSE alt_secven;]
END CASE;

sau

CASE
WHEN condiie_1 THEN secvena_de_comenzi_1;
WHEN condiie_2 THEN secvena_de_comenzi_2,

WHEN condiie_k THEN secvena_de_comenzi_k;
[ELSE alta_secvena;]
END CASE [eticheta];

Clauza ELSE este opional.
Dac aceasta este necesar n implementarea unei probleme, dar practic lipsete, iar test_var
nu ia nici una dintre valorile ce apar n clauzele WHEN, atunci se declaneaz eroarea
predefinit CASE_NOT_FOUND (ORA - 6592).

DECLARE
v_cod employees.employee_id%TYPE:=&p_cod;
v_bonus NUMBER(8);
v_salariu_anual NUMBER(8);
BEGIN
SELECT salary*12 INTO v_salariu_anual
FROM employees
WHERE employee_id = v_cod;
CASE WHEN v_salariu_anual>=20001
THEN v_bonus:=2000;
WHEN v_salariu_anual BETWEEN 10001 AND 20000
THEN v_bonus:=1000;
ELSE v_bonus:=500;
END CASE;
DBMS_OUTPUT.PUT_LINE('Bonusul este ' || v_bonus);
END;
/
9. Scriei un bloc PL/SQL n care stocai prin variabile de substituie un cod de angajat, un cod de
departament i procentul cu care se mrete salariul acestuia. S se mute salariatul n noul
departament i s i se creasc salariul n mod corespunztor. Dac modificarea s-a putut realiza
(exist n tabelul emp_*** un salariat avnd codul respectiv) s se afieze mesajul Actualizare
realizata, iar n caz contrar mesajul Nu exista un angajat cu acest cod. Anulai modificrile
realizate.
DEFINE p_cod_sal= 200
DEFINE p_cod_dept = 80
DEFINE p_procent =20
DECLARE
v_cod_sal emp_***.employee_id%TYPE:= &p_cod_sal;
v_cod_dept emp_***.department_id%TYPE:= &p_cod_dept;
v_procent NUMBER(8):=&p_procent;

SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

7
BEGIN
UPDATE emp_***
SET department_id = v_cod_dept,
salary=salary + (salary* v_procent/100)
WHERE employee_id= v_cod_sal;
IF SQL%ROWCOUNT =0 THEN
DBMS_OUTPUT.PUT_LINE('Nu exista un angajat cu acest cod');
ELSE DBMS_OUTPUT.PUT_LINE('Actualizare realizata');
END IF;
END;
/
ROLLBACK;
10. Creai tabelul zile_***(id, data, nume_zi). Introducei n tabelul zile_*** informaiile
corespunztoare tuturor zilelor care au rmas din luna curent.

LOOP
secvena_de_comenzi
END LOOP;

Comanda se execut cel puin o dat.
Dac nu este utilizat comanda EXIT, ciclarea ar putea continua la infinit.

DECLARE
contor NUMBER(6) := 1;
v_data DATE;
maxim NUMBER(2) := LAST_DAY(SYSDATE)-SYSDATE;
BEGIN
LOOP
v_data := sysdate+contor;
INSERT INTO zile_***
VALUES (contor,v_data,to_char(v_data,'Day'));
contor := contor + 1;
EXIT WHEN contor > maxim;
END LOOP;
END;
/
11. Rezolvai cerina anterioar folosind instruciunea WHILE.

WHILE condiie LOOP
secvena_de_comenzi
END LOOP;

Dac condiia este evaluat ca fiind FALSE sau NULL, atunci secvena de comenzi nu este
executat i controlul trece la instruciunea dup END LOOP.

DECLARE
contor NUMBER(6) := 1;
v_data DATE;
maxim NUMBER(2) := LAST_DAY(SYSDATE)-SYSDATE;

SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

8
BEGIN
WHILE contor <= maxim LOOP
v_data := sysdate+contor;
INSERT INTO zile_***
VALUES (contor,v_data,to_char(v_data,'Day'));
contor := contor + 1;
END LOOP;
END;
/

12. Rezolvai cerina anterioar folosind instruciunea FOR.

FOR contor_ciclu IN [REVERSE] lim_inf..lim_sup LOOP
secvena_de_comenzi;
END LOOP;

Variabila contor_ciclu nu trebuie declarat, ea fiind implicit de tip BINARY_INTEGER.
Aceasta este neidentificat n afara ciclului.
Pasul are implicit valoarea 1 i nu poate fi modificat.
Limitele domeniului pot fi variabile sau expresii, dar care pot fi convertite la ntreg.

DECLARE
v_data DATE;
maxim NUMBER(2) := LAST_DAY(SYSDATE)-SYSDATE;
BEGIN
FOR contor IN 1..maxim LOOP
v_data := sysdate+contor;
INSERT INTO zile_***
VALUES (contor,v_data,to_char(v_data,'Day'));
END LOOP;
END;
/
13. S se declare i s se iniializeze cu 1 variabila i de tip POZITIVE i cu 10 constanta max_loop
de tip POZITIVE. S se implementeze un ciclu LOOP care incrementeaz pe i pn cnd acesta
ajunge la o valoare > max_loop, moment n care ciclul LOOP este prsit i se sare la instruciunea
i:=1.
Obs. Se utilizeaz instruciunile GOTO/EXIT.

Instruciunea EXIT permite ieirea dintr-un ciclu. Controlul trece fie la prima instruciune
situat dup END LOOP-ul corespunztor, fie la instruciunea avnd eticheta nume_eticheta.

EXIT [nume_eticheta] [WHEN condiie];

Numele etichetelor urmeaz aceleai reguli ca cele definite pentru identificatori. Eticheta se
plaseaz naintea comenzii, fie pe aceeai linie, fie pe o linie separat. Etichetele se definesc
prin intercalare ntre << i >>.

GOTO nume_eticheta;

Nu este permis saltul:
n interiorul unui bloc (subbloc);
n interiorul unei comenzi IF, CASE sau LOOP;
SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

9
de la o clauz a comenzii CASE, la alt clauz aceleai comenzi;
de la tratarea unei excepii, n blocul curent;
n exteriorul unui subprogram.

Varianta 1
DECLARE
i POSITIVE:=1;
max_loop CONSTANT POSITIVE:=10;
BEGIN
LOOP
i:=i+1;
IF i>max_loop THEN
DBMS_OUTPUT.PUT_LINE('in loop i=' || i);
GOTO urmator;
END IF;
END LOOP;
<<urmator>>
i:=1;
DBMS_OUTPUT.PUT_LINE('dupa loop i=' || i);
END;
/

Varianta 2
DECLARE
i POSITIVE:=1;
max_loop CONSTANT POSITIVE:=10;
BEGIN
i:=1;
LOOP
i:=i+1;
DBMS_OUTPUT.PUT_LINE('in loop i=' || i);
EXIT WHEN i>max_loop;
END LOOP;
i:=1;
DBMS_OUTPUT.PUT_LINE('dupa loop i=' || i);
END;
/


Exerciii

1. Se d urmtorul bloc:

DECLARE
numar number(3):=100;
mesaj1 varchar2(255):='text 1';
mesaj2 varchar2(255):='text 2';
BEGIN
DECLARE
numar number(3):=1;
mesaj1 varchar2(255):='text 2';
mesaj2 varchar2(255):='text 3';

SGBD An III Sem. I Lect. Univ. Dr. Gabriela Mihai

10
BEGIN
numar:=numar+1;
mesaj2:=mesaj2||' adaugat in sub-bloc';
END;
numar:=numar+1;
mesaj1:=mesaj1||' adaugat un blocul principal';
mesaj2:=mesaj2||' adaugat in blocul principal';
END;

a) Valoarea variabilei numar n subbloc este:
b) Valoarea variabilei mesaj1 n subbloc este:
c) Valoarea variabilei mesaj2 n subbloc este:
d) Valoarea variabilei numar n bloc este:
e) Valoarea variabilei mesaj1 n bloc este:
f) Valoarea variabilei mesaj2 n bloc este:
Verificai rspunsul.

2. Se d urmtorul enun: Pentru fiecare zi a lunii octombrie (se vor lua n considerare i zilele din
lun n care nu au fost realizate mprumuturi) obinei numrul de mprumuturi efectuate.
a. ncercai s rezolvai problema n SQL fr a folosi structuri ajuttoare.
b. Definii tabelul octombrie_*** (id, data). Folosind PLSQL populai cu date acest tabel.
Rezolvai n SQL problema dat.
3. Definii un bloc anonim n care s se determine numrul de filme (titluri) mprumutate de un
membru al crui nume este introdus de la tastatur. Tratai urmtoarele dou situaii: nu exist nici
un membru cu nume dat; exist mai muli membrii cu acelai nume.
4. Modificai problema anterioar astfel nct s afiai i urmtorul text:
- Categoria 1 (a mprumutat mai mult de 75% din titlurile existente)
- Categoria 2 (a mprumutat mai mult de 50% din titlurile existente)
- Categoria 3 (a mprumutat mai mult de 25% din titlurile existente)
- Categoria 4 (altfel)
5. Creai tabelul member_*** (o copie a tabelului member). Adugai n acest tabel coloana
discount, care va reprezenta procentul de reducere aplicat pentru membrii, n funcie de categoria
din care fac parte acetia:
- 10% pentru membrii din Categoria 1
- 5% pentru membrii din Categoria 1
- 3% pentru membrii din Categoria 1
- nimic
Actualizai coloana discount pentru un membru al crui cod este dat de la tastatur. Afiai un
mesaj din care s reias dac actualizarea s-a produs sau nu.

S-ar putea să vă placă și