06.09.2014 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!