Laborator 5. Colectii de date PL/SQL In multe limbaje de ...
Laborator 5. Colectii de date PL/SQL In multe limbaje de ...
Laborator 5. Colectii de date PL/SQL In multe limbaje de ...
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
<strong>Laborator</strong> <strong>5.</strong> <strong>Colectii</strong> <strong>de</strong> <strong>date</strong> <strong>PL</strong>/<strong>SQL</strong><br />
<strong>In</strong> <strong>multe</strong> <strong>limbaje</strong> <strong>de</strong> programare folosim colectii <strong>de</strong> <strong>date</strong> cum ar fi: vectori, liste, tabele,<br />
multimi si arbori. Aceste tipuri <strong>de</strong> <strong>date</strong> pot fi mo<strong>de</strong>late in aplicatiile cu baze <strong>de</strong> <strong>date</strong> folosind<br />
<strong>PL</strong>/<strong>SQL</strong> - TABLE si VARRAY, care permit <strong>de</strong>clararea tabelelor, vectorilor <strong>de</strong> dimensiune<br />
fixa sau variabila.<br />
<br />
COLECTIILE <strong>PL</strong>/<strong>SQL</strong><br />
<strong>PL</strong>/<strong>SQL</strong> ofera umaratoarele tipuri <strong>de</strong> colectii:<br />
<br />
<br />
Tabelele grupate(nested) in care se pastreaza un numar arbitrar <strong>de</strong> elemente.<br />
Putem <strong>de</strong>fini tipuri <strong>SQL</strong> echivalente care sa permita ca tabele grupate sa fie<br />
pastrate in baza <strong>de</strong> <strong>date</strong> si sa fie manipulate folosind <strong>SQL</strong>.<br />
Tabelele in<strong>de</strong>xate; sunt similare cu tabelele <strong>de</strong> dispersie din alte <strong>limbaje</strong> <strong>de</strong><br />
programare<br />
Vectorii <strong>de</strong> dimensiune fixa (varray) pastreaza un numar fix <strong>de</strong> elemente.<br />
Putem <strong>de</strong>fini tipuri <strong>SQL</strong> echivalente care sa permita ca vectorii sa fie pastrati in<br />
baza <strong>de</strong> <strong>date</strong> si manipulati folosind <strong>SQL</strong>, dar cu mai putina flexibilitate <strong>de</strong>cat<br />
tabelele grupate.<br />
<br />
<strong>Colectii</strong> care <strong>de</strong>si au o singura dimensiune, pot fi mo<strong>de</strong>late in vectori<br />
multidimensionali prin crearea <strong>de</strong> colectii ale caror elemente sunt <strong>de</strong> asemenea<br />
colectii.<br />
o Ce sunt tabelele grupate (nested tables)<br />
Tabelele grupate in <strong>PL</strong>/<strong>SQL</strong> reprezinta multimi <strong>de</strong> valori. Sunt asemanatoare<br />
cu un vector unidimensional fara a–i <strong>de</strong>clara dimensiunea (numarul <strong>de</strong><br />
elemente). Putem crea vectori multidimensionali prin crearea <strong>de</strong> tabele grupate<br />
ale caror elemente sunt tot tabele grupate.<br />
Oracle stocheaza intr-o ordine oarecare inregistrarile dintr-o tabela grupata.<br />
Cand se citeste o tabela grupata din baza <strong>de</strong> <strong>date</strong> intr-o variabila <strong>PL</strong>/<strong>SQL</strong>,<br />
randurile sunt in<strong>de</strong>xate cu in<strong>de</strong>csi consecutive incepand cu 1. Aceasta permite<br />
accesul la inregistrari individuale.<br />
Diferentele intre tabele grupate si vectori:<br />
1. Tabelele grupate nu au un numar stabilit <strong>de</strong> elemente ; dimensiunea unei tabele<br />
grupate poate creste dinamic; totusi se impune o limita maxima a numarului <strong>de</strong><br />
elemente (1 .. 2147483647)<br />
2. Tabelele grupate pot sa nu aiba in<strong>de</strong>sci consecutivi. Se pot sterge elemente<br />
dintr-o tabela grupata folosind procedura DELETE. Functia NEXT permite<br />
iterarea elementelor dintr-o tabela grupata.<br />
Exemplu: TYPE tblNumber IS TABLE OF NUMBER;<br />
o Vectori <strong>de</strong> dimensiune fixa (Varrays)
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
Exemplu: TYPE gra<strong>de</strong>s IS vararray(10) OF VARCHAR2(64);<br />
o Vectori asociati (tabele in<strong>de</strong>xate)<br />
Vectorii asociati sunt multimi <strong>de</strong> perechi (cheie, valoare); cheia este unica si<br />
este folosita pentru a localiza valoarea corespunzatoare in vector. Cheia poate<br />
fi intreg sau sir <strong>de</strong> caractere.<br />
Exemplu: <strong>de</strong>clararea tipurilor <strong>de</strong> colectii<br />
DECLARE TYPE population_type IS TABLE OF NUMBER INDEX BY VARCHAR2(64);<br />
country_population population_type;<br />
continent_population population_type;<br />
howmany NUMBER;<br />
which VARCHAR2(64);<br />
BEGIN<br />
country_population('Greenland') := 100000; -- adauga o noua intrare<br />
country_population('Iceland') := 750000; -- adauga o noua intrare<br />
--Cautam o valoare in tabel corespunzatoare in<strong>de</strong>xului 'Greenland'.<br />
howmany := country_population('Greenland');<br />
continent_population('Australia') := 30000000;<br />
continent_population('Antarctica') := 1000; -- adauga o noua intrare<br />
continent_population('Antarctica') := 1001; -- inlocuieste vechea valoare<br />
--meto<strong>de</strong>le FIRST si LAST returneaza primul, respectiv ultimul in<strong>de</strong>x al colectiei<br />
which := continent_population.FIRST;<br />
--!Afisati which<br />
which := continent_population.LAST;<br />
--!Afisati which<br />
howmany := continent_population(continent_population.LAST);<br />
--!Afisati howmany<br />
END;<br />
Deoarece vectorii asociati sunt folositi pentru a memora <strong>date</strong> temporare, in loc<br />
<strong>de</strong> a memora <strong>date</strong> persistente, ei nu pot fi utilizate in comenzi <strong>SQL</strong> cum ar fi<br />
INSERT si SELECT INTO.<br />
Acestia pot <strong>de</strong>veni <strong>date</strong> persistente pentru o sesiune a bazei <strong>de</strong> <strong>date</strong> prin<br />
<strong>de</strong>clararea tipului intr-un pachet si atribuirea <strong>de</strong> valori in corpul pachetului.<br />
DEFINIREA COLECTIILOR SI DECLARAREA VARIABILELOR DE TIP<br />
COLECTIE<br />
Pentru a crea colectii, se poate <strong>de</strong>fini un tip <strong>de</strong> <strong>date</strong> colectie in sectiunea <strong>de</strong> <strong>de</strong>claratii.<br />
Exemplu: <strong>de</strong>clararea unei variabile <strong>de</strong> tipul VARRAY<br />
DECLARE<br />
TYPE Calendar IS VARRAY(366) OF DATE;<br />
Vectorii asociati (numiti si tabele in<strong>de</strong>xate) permit inserarea <strong>de</strong> elemente cu chei<br />
arbitare. Cheile pot sa nu fie consecutive.
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
Tipul <strong>de</strong> <strong>date</strong> pentru cheie poate fi: <strong>PL</strong>S_INTEGER, BINARY_INTEGER, sau<br />
VARCHAR2, sau unul dintre subtipurile tipului VARCHAR2: VARCHAR, STRING,<br />
sau LONG. <strong>PL</strong>S_INTEGER si BINARY_INTEGER sunt i<strong>de</strong>ntice.<br />
Exemplu: <strong>de</strong>clararea unei variabile <strong>de</strong> tipul vector asociat(tabel in<strong>de</strong>xat)<br />
DECLARE<br />
TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE INDEX BY <strong>PL</strong>S_INTEGER;<br />
emp_tab EmpTabTyp;<br />
BEGIN<br />
/* selectarea angajatului si salvarea lui in variabila emp_tab */<br />
SELECT * INTO emp_tab(1) FROM employees WHERE employee_id = 100;<br />
END;<br />
Observatie: pentru a adauga mai <strong>multe</strong> intregistrari trebuie creat un cursor (vezi<br />
laboratorul 3 (pg.4-5), exemplu cursor implicit)<br />
o Declararea variabilelor <strong>de</strong> tip colectie in <strong>PL</strong>/<strong>SQL</strong><br />
Exemplu: <strong>de</strong>clararea tabelelor grupate, a vectorilor cu dimensiune fixa, vectori<br />
asociati<br />
DECLARE<br />
TYPE nested_type IS TABLE OF VARCHAR2(30);<br />
TYPE varray_type IS VARRAY(5) OF INTEGER;<br />
TYPE assoc_array_num_type IS TABLE OF NUMBER INDEX BY <strong>PL</strong>S_INTEGER;<br />
TYPE assoc_array_str_type IS TABLE OF VARCHAR2(32) INDEX BY <strong>PL</strong>S_INTEGER;<br />
TYPE assoc_array_str_type2 IS TABLE OF VARCHAR2(32) INDEX BY VARCHAR2(64);<br />
v1 nested_type;<br />
v2 varray_type;<br />
v3 assoc_array_num_type;<br />
v4 assoc_array_str_type;<br />
v5 assoc_array_str_type2;<br />
BEGIN<br />
--initializare<br />
v1 := nested_type('Shipping','Sales','Finance','Payroll');<br />
v2 := varray_type(1, 2, 3, 4, 5); -- numai 5 intregi poti fi aduagati, <strong>de</strong>oarece dim maxima este 5<br />
v3(99) := 10;<br />
v3(7) := 100; -- subscripturile pot fi numai numere intregi<br />
v4(42) := 'Smith'; -- subscripturile pot fi numai numere intregi<br />
v4(54) := 'Jones';<br />
v5('Canada') := 'North America'; -- subscripturile pot fi si siruri <strong>de</strong> caractere<br />
v5('Greece') := 'Europe';<br />
END;<br />
Exemplu: <strong>de</strong>clararea colectiilor folosind %TYPE<br />
DECLARE<br />
TYPE few_<strong>de</strong>pts IS VARRAY(10) OF VARCHAR2(30);<br />
TYPE many_<strong>de</strong>pts IS VARRAY(100) OF VARCHAR2(64);<br />
some_<strong>de</strong>pts few_<strong>de</strong>pts;<br />
local_<strong>de</strong>pts some_<strong>de</strong>pts%TYPE;<br />
global_<strong>de</strong>pts some_<strong>de</strong>pts%TYPE;<br />
BEGIN<br />
NULL;<br />
END;
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
o <strong>In</strong>itializarea si referirea colectiilor<br />
Exemplu: initializarea unei tabele grupate folosind un constructor(care apare ca o<br />
functie cu acelasi nume ca si tipul colectiei):<br />
DECLARE<br />
TYPE dnames_tab IS TABLE OF VARCHAR2(30);<br />
<strong>de</strong>pt_names dnames_tab;<br />
BEGIN<br />
<strong>de</strong>pt_names := dnames_tab('Shipping','Sales','Finance','Payroll');<br />
END;<br />
Deoarece o tabela grupata nu are o dimensiune fixa <strong>de</strong>clarata, se pot pune cate<br />
elemente se doresc in constructor.<br />
Exemplu: initializarea unui vector <strong>de</strong> dimensiune fixa folosind un constructor<br />
care apare ca o functie cu acelasi nume ca tipul colectiei:<br />
DECLARE<br />
--in vector se pune limita superioara pentru numarul <strong>de</strong> elemente<br />
TYPE dnames_var IS VARRAY(20) OF VARCHAR2(30);<br />
<strong>de</strong>pt_names dnames_var;<br />
BEGIN<br />
<strong>de</strong>pt_names := dnames_var('Shipping','Sales','Finance','Payroll');<br />
END;<br />
Daca in <strong>de</strong>claratia tipului nu este <strong>de</strong>finita constrangerea NULL, se pot transmite si<br />
elemente nule in constructor.<br />
Exemplu:<br />
DECLARE<br />
TYPE dnames_tab IS TABLE OF VARCHAR2(30);<br />
<strong>de</strong>pt_names dnames_tab;<br />
TYPE dnamesNoNulls_type IS TABLE OF VARCHAR2(30) NOT NULL;<br />
BEGIN<br />
<strong>de</strong>pt_names := dnames_tab('Shipping', NULL,'Finance', NULL);<br />
END;<br />
Daca constructorul apelat este fara argumente atunci se va crea o colectie vida.<br />
DECLARE<br />
TYPE dnames_var IS VARRAY(20) OF VARCHAR2(30);<br />
<strong>de</strong>pt_names dnames_var;<br />
BEGIN<br />
IF <strong>de</strong>pt_names IS NULL THEN<br />
DBMS_OUTPUT.PUT_LINE('<strong>In</strong>ainte <strong>de</strong> initializare, vectorul este nul.');<br />
-- <strong>de</strong>oarece vectorul este nul nu putem sa verificam atributul COUNT<br />
-- DBMS_OUTPUT.PUT_LINE(Vectorul are ' || <strong>de</strong>pt_names.COUNT || ' elemente.');
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
ELSE<br />
DBMS_OUTPUT.PUT_LINE('<strong>In</strong>ainte <strong>de</strong> initializare, vectorul nu este nul.');<br />
END IF;<br />
<strong>de</strong>pt_names := dnames_var(); -- initializarea vectorului<br />
IF <strong>de</strong>pt_names IS NULL THEN<br />
DBMS_OUTPUT.PUT_LINE('Dupa initializare, vectorul este nul.');<br />
ELSE<br />
DBMS_OUTPUT.PUT_LINE('<strong>In</strong>ainte <strong>de</strong> initializare, vectorul nu este nul.');<br />
DBMS_OUTPUT.PUT_LINE('Vectorul are ' || <strong>de</strong>pt_names.COUNT || ' elemente.');<br />
END IF;<br />
END;<br />
o Cum accesam elementele din colectii<br />
Fiecare referire la un element dintr-o colectie implica numele colectiei si in<strong>de</strong>xul<br />
(subscriptul) inchis intre paranteze rotun<strong>de</strong>.<br />
collection_name(in<strong>de</strong>x)<br />
un<strong>de</strong> in<strong>de</strong>x este o expresie care este un intreg in cele mai <strong>multe</strong> cazuri dar poate fi<br />
si un VARCHAR2 pentru vectorii asociati in care cheile sunt <strong>de</strong>clarate ca siruri <strong>de</strong><br />
caractere.<br />
Limitele pentru subscript sunt:<br />
Pentru tabele grupate: 1 .. 2147483647<br />
Pentru vectori cu dim fixa 1 .. size_limit, (size_limit nu <strong>de</strong>paseste<br />
2147483647).<br />
Pentru vectorii asociati cu chei numerice -2147483648 la 2147483647.<br />
Pentru vectorii asociati cu chei <strong>de</strong> tip string lungimea cheii <strong>de</strong>pin<strong>de</strong> <strong>de</strong><br />
<strong>de</strong>claratia tipului VARCHAR2.<br />
Exemplu:<br />
DECLARE<br />
TYPE Roster IS TABLE OF VARCHAR2(15);<br />
names Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');<br />
BEGIN<br />
FOR i IN names.FIRST .. names.LAST<br />
LOOP<br />
IF names(i) = 'J Hamil' THEN<br />
DBMS_OUTPUT.PUT_LINE(names(i));<br />
END IF;<br />
END LOOP;<br />
verify_name(names(3));<br />
END;<br />
--creati procedura<br />
PROCEDURE list_name(the_name VARCHAR2) IS<br />
BEGIN<br />
DBMS_OUTPUT.PUT_LINE(the_name);<br />
END;<br />
Exemplu:
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010<br />
DECLARE<br />
TYPE sum_multiples IS TABLE OF <strong>PL</strong>S_INTEGER INDEX BY <strong>PL</strong>S_INTEGER;<br />
n <strong>PL</strong>S_INTEGER := 5;<br />
sn <strong>PL</strong>S_INTEGER := 10;<br />
m <strong>PL</strong>S_INTEGER := 3;<br />
BEGIN<br />
DBMS_OUTPUT.PUT_LINE('Suma primelor ' || TO_CHAR(n) || ' inmultite cu ' ||<br />
TO_CHAR(m) || ' este ' || TO_CHAR(get_sum_multiples (m, sn)));<br />
END;<br />
--creati functia<br />
FUNCTION get_sum_multiples(multiple IN <strong>PL</strong>S_INTEGER, num IN <strong>PL</strong>S_INTEGER)<br />
RETURN sum_multiples IS<br />
s sum_multiples;<br />
BEGIN<br />
FOR i IN 1..num LOOP<br />
s(i) := multiple * ((i * (i + 1)) / 2) ;<br />
END LOOP;<br />
RETURN s;<br />
END get_sum_multiples;<br />
o Atribuirea <strong>de</strong> elemente unei colectii<br />
colectie1(in<strong>de</strong>x) := colectie2;<br />
un<strong>de</strong> colectie2 este o alta colectie cu acelasi tip cu elementele ca si colectie1.<br />
Se pot folosi si operatorii pentru atribuiri <strong>de</strong> colectii: SET, MULTISET UNION,<br />
MULTISET INTERSECT si MULTISET EXCEPT.<br />
Exemplu: compatibilitate <strong>de</strong> tip la atribuirea colectiilor<br />
DECLARE<br />
TYPE last_name_typ IS VARRAY(3) OF VARCHAR2(64);<br />
TYPE surname_typ IS VARRAY(3) OF VARCHAR2(64);<br />
-- aceste 2 var au acelasi tip <strong>de</strong> data.<br />
group1 last_name_typ := last_name_typ('Jones','Wong','Marceau');<br />
group2 last_name_typ := last_name_typ('Klein','Patsos','Singh');<br />
-- a 3-a var are o <strong>de</strong>claratie asemanatoare dar n uare acelasi tip<br />
group3 surname_typ := surname_typ('Trevisi','Macleod','Marquez');<br />
BEGIN<br />
group1 := group2;<br />
--group3 := group2; -- se genereaza o eroare<br />
END;<br />
Exemplu: atribuirea tabelelor grupate folosind operatorii SET, MULTISET<br />
UNION, MULTISET INTERSECT si MULTISET EXCEPT<br />
DECLARE<br />
TYPE nested_typ IS TABLE OF NUMBER;<br />
nt1 nested_typ := nested_typ(1,2,3);<br />
nt2 nested_typ := nested_typ(3,2,1);<br />
nt3 nested_typ := nested_typ(2,3,1,3);
nt4 nested_typ := nested_typ(1,2,4);<br />
answer nested_typ;<br />
BEGIN<br />
answer := nt1 MULTISET UNION nt4; -- (1,2,3,1,2,4)<br />
print_nested_table(answer);<br />
answer := nt1 MULTISET UNION nt3; -- (1,2,3,2,3,1,3)<br />
print_nested_table(answer);<br />
answer := nt1 MULTISET UNION DISTINCT nt3; -- (1,2,3)<br />
print_nested_table(answer);<br />
answer := nt2 MULTISET INTERSECT nt3; -- (3,2,1)<br />
print_nested_table(answer);<br />
answer := nt2 MULTISET INTERSECT DISTINCT nt3; -- (3,2,1)<br />
print_nested_table(answer);<br />
answer := SET(nt3); -- (2,3,1)<br />
print_nested_table(answer);<br />
answer := nt3 MULTISET EXCEPT nt2; -- (3)<br />
print_nested_table(answer);<br />
answer := nt3 MULTISET EXCEPT DISTINCT nt2; -- ()<br />
print_nested_table(answer);<br />
END;<br />
--creati procedura<br />
PROCEDURE print_nested_table(the_nt nested_typ) IS<br />
output VARCHAR2(128);<br />
BEGIN<br />
IF the_nt IS NULL THEN<br />
DBMS_OUTPUT.PUT_LINE('Results: ');<br />
RETURN;<br />
END IF;<br />
IF the_nt.COUNT = 0 THEN<br />
DBMS_OUTPUT.PUT_LINE('Results: empty set');<br />
RETURN;<br />
END IF;<br />
FOR i IN the_nt.FIRST .. the_nt.LAST<br />
LOOP<br />
output := output || the_nt(i) || ' ';<br />
END LOOP;<br />
DBMS_OUTPUT.PUT_LINE('Results: ' || output);<br />
END;<br />
Anca Ion, Proiectarea Bazelor <strong>de</strong> Date, 2010