Documente Academic
Documente Profesional
Documente Cultură
Baze de Date c2 - Colectii
Baze de Date c2 - Colectii
specifice PL/SQL;
nespecifice PL/SQL.
Variabile specifice PL/SQL se clasific n variabile:
de tip scalar,
compuse,
referin,
tipuri obiect.
Variabile nespecifice PL/SQL pot fi:
variabile de legtur (bind variables),
variabile gazd (host variables),
variabile indicator.
Tipurile obiect
Sunt tipuri compuse, definite de utilizator, care ncapsuleaz structuri de
date (atribute) mpreun cu subprograme pentru manipularea datelor (metode).
Dintre tipurile scalare PL/SQL, urmtoarele sunt i tipuri SQL (adic pot fi
folosite pentru coloanele tabelelor Oracle): NUMBER, VARCHAR2, CHAR,
LONG, RAW, LONG RAW, ROWID, NCHAR, NVARCHAR2, DATE. n unele
cazuri, tipurile de date PL/SQL difer de corespondentele lor SQL prin
dimensiunea maxim permis.
Tipul NUMBER memoreaz numerele n virgul fix i virgul mobil. El
are forma general NUMBER (m, n), unde m reprezint numrul total de cifre,
iar n numrul de zecimale. Valoarea unei variabile de tip NUMBER este cuprins
ntre 1.0E-129 i 9.99E125. Numrul de zecimale determin poziia n care
apare rotunjirea. Valoarea sa este cuprins ntre -84 i 127, iar implicit este 0.
Tipul NUMBER are urmtoarele subtipuri, care au aceleai intervale de
valori: NUMERIC, REAL, DEC, DECIMAL i DOUBLE PRECISION (pentru
memorarea datelor numerice n virgul fix), FLOAT (pentru memorarea datelor
numerice n virgul mobil), SMALLINT, INTEGER i INT (pentru memorarea
numerelor ntregi). Aceste subtipuri se pot utiliza pentru compatibilitate
ANSI/ISO, IBM SQL/DS sau IBM DB2.
Tipul BINARY_INTEGER memoreaz numere ntregi cu semn avnd
valori cuprinse ntre -231 - 1 i 231 - 1. Acest tip de date este utilizat frecvent
pentru indecii tabelelor, nu necesit conversii i admite mai multe subtipuri. De
exemplu, pentru a restriciona domeniul variabilelor la valori ntregi nenegative
se utilizeaz tipurile NATURAL (0 .. 231 1) i POSITIVE (1 .. 231 1).
Tipul PLS_INTEGER este utilizat pentru stocarea numerelor ntregi cu
semn i are acelai interval de definire ca i tipul BINARY_INTEGER. Operaiile
cu acest tip sunt efectuate mai rapid (folosesc aritmetica mainii), dect cele cu
tipurile NUMBER sau BINARY_INTEGER (folosesc librrii aritmetice). Prin
urmare, pentru o mai bun performan, este preferabil s se utilizeze tipul
PLS_INTEGER.
Declararea variabilelor
Identificatorii PL/SQL trebuie declarai nainte de a fi 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.
Tipurile scalare sunt predefinite n pachetul STANDARD. Pentru a folosi
un astfel de tip ntr-un program este suficient s fie declarat o variabil de tipul
respectiv.
Tipurile compuse sunt definite de utilizator. Prin urmare, n acest caz
trebuie definit efectiv tipul i apoi declarat variabila de tipul respectiv.
Observaii:
1. Pentru a denumi o variabil este utilizat frecvent (pentru uurina referirii)
prefixarea cu litera v (v_identificator), iar pentru o constant este folosit
prefixarea cu litera c (c_identificator).
2. Variabilele pot fi iniializate, iar dac o variabil nu este iniializat, valoarea
implicit a acesteia este null. Dac o variabil este declarat NOT NULL,
atunci ea va fi obligatoriu iniializat.
3. Pentru a iniializa o variabil sau o constant poate fi utilizat o expresie
PL/SQL compatibil ca tip cu variabila sau constanta respectiv.
Definirea subtipurilor
Subtipurile deriv dintr-un tip de baz, la care se adaug anumite restricii.
De exemplu, NATURAL este un subtip predefinit PL/SQL, derivat din tipul de
baz BINARY_INTEGER, cu restricia c permite prelucrarea valorilor ntregi
nenegative.
Prin urmare, un subtip nu reprezint un nou tip de date, ci un tip existent
asupra cruia se aplic anumite constrngeri. Subtipurile presupun acelai set de
operaii ca i tipul de baz, dar aplicate unui subset de valori al acestui tip.
Sistemul Oracle permite ca utilizatorul s-i defineasc propriile sale
tipuri i subtipuri de date n partea declarativ a unui bloc PL/SQL, subprogram
sau pachet utiliznd sintaxa:
SUBTYPE nume_subtip IS tip_de_baza [NOT NULL];
n dicionarul datelor exist vizualizri care furnizeaz informaii despre
tipurile de date create de utilizator (USER_TYPES, USER_TYPE_ATTRS).
nregistrri
Tipul RECORD ofer un mecanism pentru prelucrarea nregistrrilor.
nregistrrile au mai multe cmpuri ce pot fi de tipuri diferite, dar care sunt
legate din punct de vedere logic.
Inregistrrile trebuie definite n doi pai:
se definete tipul RECORD;
se declar nregistrrile de acest tip.
Declararea tipului RECORD se face conform urmtoarei sintaxe:
TYPE nume_tip IS RECORD
(nume_cmp1 {tip_cmp | variabil%TYPE |
nume_tabel.coloan%TYPE | nume_tabel%ROWTYPE}
[ [NOT NULL] {:= | DEFAULT} expresie1],
(nume_cmp2 {tip_cmp | variabil%TYPE |
nume_tabel.coloan%TYPE | nume_tabel%ROWTYPE}
[ [NOT NULL] {:= | DEFAULT} expresie2],);
Identificatorul nume_tip reprezint numele tipului RECORD care se va
specifica n declararea nregistrrilor, nume_cmp este numele unui cmp al
nregistrrii, iar tip_cmp este tipul de date al cmpului.
Observaii:
END;
Colecii
Uneori este preferabil s fie prelucrate simultan mai multe variabile de
acelai tip. Tipurile de date care permit acest lucru sunt coleciile. Fiecare
element are un indice unic, care determin poziia sa n colecie.
Oracle7 a furnizat tipul index-by table, iniial numit PL/SQL table datorit
asemnrii sale cu structura tabelelor relaionale.
10
Observaii:
Deoarece coleciile nu pot fi comparate (egalitate sau inegalitate), ele
nu pot s apar n clauzele DISTINCT, GROUP BY, ORDER BY.
Tipul colecie poate fi definit ntr-un pachet.
Tipul colecie poate s apar n clauza RETURN a unei funcii.
Coleciile pot fi parametri formali ntr-un subprogram.
Accesul la elementele individuale ale unei colecii se face prin
utilizarea unui indice.
Tablouri indexate
Tipul de date index-by table ofer un mecanism pentru prelucrarea
tablourilor. Tabloul indexat PL/SQL are dou componente: o coloan ce
cuprinde cheia primar pentru acces la liniile tabloului i o coloan care include
valoarea efectiv a elementelor tabloului.
11
12
13
Vectori
Vectorii (varray) sunt structuri asemntoare vectorilor din limbajele C
sau Java. Spre deosebire de tablourile indexate, vectorii au o dimensiune
maxim (constant) stabilit la declarare. n special, se utilizeaz pentru
modelarea relaiilor one-to-many, atunci cnd numrul maxim de elemente din
partea many este cunoscut i ordinea elementelor este important.
Vectorii reprezint structuri dense. Fiecare element are un index care d
poziia sa n vector i care este folosit pentru accesarea elementelor particulare.
Limita inferioar a indicelui este 1. Vectorul poate conine un numr variabil de
elemente, de la 0 (vid) la numrul maxim specificat obligatoriu n definiia sa.
Tipul de date vector este declarat utiliznd sintaxa:
TYPE nume_tip IS
{VARRAY | VARYING ARRAY} (lungime_maxim)
OF tip_elemente [NOT NULL];
14
Tablouri imbricate
Tablourile imbricate (nested table) sunt tablouri indexate a cror
dimensiune nu este stabilit. Numrul maxim de linii ale unui tablou imbricat
este dat de capacitatea maxim 2 GB.
Un tablou imbricat este o mulime neordonat de elemente de acelai tip.
Valorile de acest tip:
-- pot fi stocate n baza de date,
-- pot fi prelucrate direct n instruciuni SQL
-- au excepii predefinite proprii.
Sistemul Oracle nu stocheaz liniile unui tablou imbricat ntr-o ordine
particular. Dar, cnd se regsete tabloul n variabile PL/SQL, liniile vor avea
indici consecutivi ncepnd cu valoarea 1. Iniial, aceste tablouri sunt structuri
dense, dar se poate ca n urma prelucrrii s nu mai aib indici consecutivi.
Comanda de declarare a tipului de date tablou imbricat are sintaxa:
TYPE nume_tip IS TABLE OF tip_ elemente [NOT NULL];
Identificatorul nume_tip reprezint numele noului tip de date tablou
imbricat, iar tip_elemente este tipul fiecrui element din tabloul imbricat, care
poate fi un tip definit de utilizator sau o expresie cu %TYPE, respectiv
%ROWTYPE.
15
n Oracle9i sunt permise (pentru tip_elemente) tipurile TABLE sau alt tip
VARRAY. Exist restricii referitoare la tipul elementelor, n sensul c acesta nu
poate s fie BOOLEAN, STRING, NCHAR, NCLOB, NVARCHAR2, REF
CURSOR, BINARY_INTEGER, PLS_INTEGER, LONG, LONG RAW,
NATURAL, NATURALN, POSITIVE, POSITIVEN, SIGNTYPE, tip obiect cu
atributele TABLE sau VARRAY.
Tabloul imbricat are o singur coloan, iar dac aceasta este de tip obiect,
tabloul poate fi vizualizat ca un tabel multicoloan, avnd cte o coloan pentru
fiecare atribut al tipului obiect.
Exemplu:
DECLARE
TYPE numartab IS TABLE OF NUMBER;
-- se creeaza un tablou cu un singur element
v_tab_1 numartab := numartab(-7);
-- se creeaza un tablou cu 4 elemente
v_tab_2 numartab := numartab(7,9,4,5);
-- se creeaza un tablou fara nici un element
v_tab_3 numartab := numartab();
BEGIN
v_tab_1(1) := 57;
FOR j IN 1..4 LOOP
DBMS_OUTPUT.PUT_LINE (v_tab_2(j) || ' ');
END LOOP;
END;
16
element (nu este iniializat), el este automat iniializat (atomic) null. Adic,
colecia este null, nu elementele sale. Prin urmare, pentru tablouri imbricate
poate fi utilizat operatorul IS NULL. Dac se ncearc s se adauge un element
la un tablou imbricat null, se va genera eroarea ORA - 06531: reference to
uninitialized
collection
care
corespunde
excepiei
predefinite
COLLECTION_IS_NULL.
Prin urmare, cum poate fi iniializat un tablou imbricat? Ca i obiectele,
vectorii i tablourile imbricate sunt iniializate cu ajutorul constructorului.
Acesta are acelai nume ca i tipul coleciei referite. PL/SQL apeleaz un
constructor numai n mod explicit. Tabelele indexate nu au constructori.
Constructorul primete ca argumente o list de valori de tip tip_elemente.
Elementele sunt numerotate n ordine, de la 1 la numrul de valori date ca
parametrii constructorului. Dimensiunea iniial a coleciei este egal cu
numrul de argumente date n constructor, cnd aceasta este iniializat. Pentru
vectori nu poate fi depit dimensiunea maxim precizat la declarare. Atunci
cnd constructorul este fr argumente, va crea o colectie fr nici un element
(vida), dar care are valoarea not null. Exemplul urmtor este concludent n acest
sens.
Exemplu:
DECLARE
TYPE alfa IS TABLE OF VARCHAR2(50);
-- creeaza un tablou (atomic) null
tab1 alfa ;
/* creeaza un tablou cu un element care este null, dar
tabloul nu este null, el este initializat, poate
primi elemente */
tab2 alfa := alfa() ;
BEGIN
IF tab1 IS NULL THEN
DBMS_OUTPUT.PUT_LINE('tab1
ELSE
DBMS_OUTPUT.PUT_LINE('tab1
END IF;
IF tab2 IS NULL THEN
DBMS_OUTPUT.PUT_LINE('tab2
ELSE
DBMS_OUTPUT.PUT_LINE('tab2
END IF;
END;
este NULL');
este NOT NULL');
este NULL');
este NOT NULL');
17
END;
Tablourile imbricate i vectorii pot fi utilizai drept cmpuri n tabelele
bazei. Aceasta presupune c fiecare nregistrare din tabelul respectiv conine un
obiect de tip colecie. nainte de utilizare, tipul trebuie stocat n dicionarul
datelor, deci trebuie declarat prin comanda:
CREATE TYPE nume_tip AS {TABLE | VARRAY} OF tip_elemente;
Dup crearea tabelului (prin comanda CREATE TABLE), pentru fiecare
cmp de tip tablou imbricat din tabel este necesar clauza de stocare:
NESTED TABLE nume_cmp STORE AS nume_tabel;
18
vbet(5) := alfa(56,33);
vbet(4) := alfa(44,66,77,4321);
vbet(4)(4) := 7; -- 4321 este inlocuit cu 7
vbet(4).EXTEND; -- se adauga un element la al 4-lea element
vbet(4)(5) := 777; -- acest nou element adaugat va fi 777
END;
/
DECLARE
TYPE gama IS TABLE OF VARCHAR2(20);
TYPE delta IS TABLE OF gama;
TYPE teta IS VARRAY(10) OF INTEGER;
19
Prelucrarea coleciilor
O colecie poate fi exploatat fie n ntregime (atomic) utiliznd comenzi
LMD, fie pot fi prelucrate elemente individuale dintr-o colecie (piecewise
updates) utiliznd operatori SQL sau anumite faciliti oferite de PL/SQL.
Comanda INSERT permite inserarea unei colecii ntr-o linie a unui
tabel. Colecia trebuie s fie creat i iniializat anterior.
Comanda UPDATE este folosit pentru modificarea unei colecii
stocate.
20
END;
Un vector stocat ntr-un tabel este prelucrat ca un ntreg (nu pot fi
modificate elemente individuale). Prin urmare, elementele individuale ale unui
vector nu pot fi referite n comenzile INSERT, UPDATE sau DELETE. Pentru
referirea acestora trebuie utilizate comenzi procedurale PL/SQL. Pentru a
modifica un vector, el trebuie selectat ntr-o variabil PL/SQL a crei valoare
poate fi modificat i apoi reinserat n tabel.
Tablourile imbricate depuse n baza de date sunt mai flexibile, deoarece
pot fi prelucrate fie n ntregime, fie ca elemente individuale. n fiecare caz pot fi
utilizate numai comenzi SQL.
Se pot face reactualizri sau inserri asupra tablourilor imbricate care dau
o valoare nou pentru ntreaga colecie sau se pot face inserri, tergeri,
reactualizri de elemente particulare din colecie.
21
22
Bulk bind
23
24
DECLARE
TYPE nume IS VARRAY(20) OF NUMBER;
alfa nume := nume(10,20,70); -- coduri ale galeriilor
BEGIN
FORALL j IN alfa.FIRST..alfa.LAST
DELETE FROM opera
WHERE cod_galerie = alfa (j);
END;
Pentru utilizarea comenzii FORALL este necesar respectarea
urmtoarelor restricii:
comanda poate fi folosit numai n programe server-side, altfel apare
eroarea this feature is not supported in client-side programs;
comenziile INSERT, UPDATE, DELETE trebuie s refere cel puin o
colecie;
toate elementele coleciei din domeniul precizat trebuie s existe
(dac, de exemplu, un element a fost ters, atunci este semnalat o
eroare);
indicii coleciilor nu pot s fie expresii i trebuie s aib valori
continue.
Exemplu:
CREATE TABLE exemplu (x NUMBER, y NUMBER);
DECLARE
TYPE nume IS TABLE OF NUMBER;
ttt
nume:= nume(1,2,3);
BEGIN
FORALL i IN ttt.FIRST..ttt.LAST
INSERT INTO exemplu
VALUES(ttt(i), 10); -- corect
FORALL i IN 1..3
INSERT INTO exemplu
VALUES(7, 9);
-- exceptie
END;
FORALL i IN gama.FIRST..gama.LAST
DELETE FROM carte
WHERE codel = gama(i+1);
-- eroare dubla (expresie si >LAST)
DECLARE
25
DECLARE
TYPE tip1 IS TABLE OF opera.cod_opera%TYPE;
26
END;
Comanda FORALL se poate combina cu clauza BULK COLLECT. Totui,
trebuie subliniat c ele nu pot fi folosite simultan n comanda SELECT.
Motorul SQL incarca toate liniile unei coloane. Cum se poate limita
numarul de linii procesate? Exemplelele urmatoare dau 2 variante de rezolvare.
DECLARE
TYPE alfa IS TABLE OF carte.pret%TYPE;
xx
alfa;
BEGIN
SELECT pret BULK COLLECT INTO xx
FROM
carte WHERE ROWNUM <= 500;
END;
DECLARE
zz NATURAL := 10;
BEGIN
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO xx, yy LIMIT zz;
EXIT WHEN c1%NOTFOUND;
END;