Pentru
descrierea tipurilor compuse se poate folosi declaratia de tip. Aceasta are
urmatoarea forma:
TYPE denumire_tip descriere_tip;
Cu
ajutorul ei vom putea defini si tipurile compuse care se pot folosi in PL/SQL:
§
Inregistrare (RECORD)
§
Tablou asociativ (TABLE .. INDEX BY)
§
Tabela (Nested TABLE)
§
Tablou de dimensiune
variabila (VARRAY)
Aceste
tipuri sunt descrise in continuare.
Inregistrarile
din PL/SQL sunt similare inregistrarilor din limbajul Pascal sau structurilor
din C. Sub un acelasi nume sunt inmagazinate mai multe valori de tipuri
diferite care se numesc campuri.
Definirea
unei inregistrari se poate face in doua moduri:
§
Folosind o descriere a
fiecarei componente a inregistrarii. In primul caz o variabila de acest tip
poate sa nu fie asociata unei tabele sau rezultatului unei cereri SQL.
§
Folosind %ROWTYPE se
poate defini o inregistrare compatibila cu o linie a unei tabele sau cu o linie
a rezultatului unei cereri SQL.
A.
Inregistrari
definite prin descrierea componentelor
In
acest caz sintaxa definirii unui tip este urmatoarea:
TYPE denumire_tip IS RECORD
(nume_camp tip_camp [NOT NULL]
[:= | DEFAULT expresie]
[, nume_camp ...]);
Tipul
unui camp poate fi oricare dintre tipurile scalare sau compuse din PL/SQL in
afara de REF CURSOR.
Referirea
unui camp al unei variabile de tip inregistrare se face cu constructia:
nume_inregistrare.nume_camp
Exemplu:
DECLARE
v_salariu NUMBER(4);
TYPE t_angajat IS RECORD
(cod NUMBER(4) NOT NULL := 1234,
nume emp.ename%type,
sal v_salariu%type,
data DATE DEFAULT SYSDATE);
v_angajat t_angajat;
BEGIN
v_angajat.cod
:= v_angajat.cod + 1;
v_angajat.nume
:= 'HERMAN';
v_angajat.sal
:= 1400;
. . .
END;
Mai
sus a fost definit un tip inregistrare numit t_angajat si o
variabila de acest tip (v_angajat). Se observa ca se poate defini
tipul unui camp si un functie de tipul unei variabile sau al unei coloane a
unei tabele. In exemplul de mai sus
toate campurile inregistrarii sunt scalare dar in cazul general ele pot fi si
compuse, de exemplu inregistrare (definite cu %ROWTYPE, descris in continuare).
B.
Inregistrari
definite cu %ROWTYPE
In
acest caz sintaxa definitiei unei variabile inregistrare este:
nume_variabila nume_tabela%ROWTYPE;
Inregistrarea
va avea atatea campuri cate coloane are tabela si acestea se vor numi la fel cu
aceste coloane. Aceste inregistrari se pot utiliza pe clauza INTO a unei cereri
SELECT * care intoarce o singura linie.
Exemplu:
DECLARE
v_angajat emp%ROWTYPE;
BEGIN
SELECT *
INTO
v_angajat
FROM emp
WHERE
empno=1234;
v_angajat.ename
:= 'HERMAN';
v_angajat.sal
:= 1400;
. . .
END;
Tablourile
asociative stocheaza perechi (cheie, valoare) unde valorile sunt de acelasi
tip. Nu au dimensiune fixata la declarare si fiecare componenta se creeaza la
prima asignare.
Caracteristici:
§
Cand sunt numerice,
cheile nu trebuie sa fie consecutive si nici sa inceapa de la 1. In Oracle8
cheia putea fi doar BINARY_INTEGER, dar incepand cu Oracle9 ea poate fi si
VARCHAR2, un subtip al VARCHAR2 sau un tip convertibil la VARCHAR2.
§
In Oracle8 valorile
puteau fi scalare sau de tip ROWTYPE. Incepand cu Oracle9 poate fi orice tip
definit anterior.
§
Elementele unei astfel
de colectii nu pot fi initializate la declarare.
§
Tablourile asociative
sunt concepute pentru a stoca date temporare ale programelor PL/SQL. De aceea
ele nu pot fi utilizate in comenzi SQL ca SELECT sau INSERT pentru a fi
regasite/stocate in baza de date.
§
Din punct de vedere al
echivalentei cu structuri de date folosite in alte limbaje de programare, ele
sunt similare tabelelor de dispersie (hash tables).
Tipuri
admise pentru cheie:
§
BINARY_INTEGER sau
PLS_INTEGER.
§
VARCHAR2(n) (in caz ca n
lipseste se ia implicit 32760) sau subtipurile sale: VARCHAR, STRING, LONG.
§
Tipuri convertibile la
VARCHAR2 cum sunt DATE, TIMESTAMP.
Tipuri
care nu sunt admise pentru cheie:
§
RAW, LONG RAW, ROWID
§
CHAR, CHARACTER.
Sintaxa
declararii unui tablou asociativ:
TYPE nume_tip IS TABLE OF tip_element [NOT NULL]
INDEX BY [BINARY_INTEGER | PLS_INTEGER |
VARCHAR2(dimensiune_maxima_sir)];
Exemplu:
DECLARE
TYPE t_varsta IS TABLE OF NUMBER INDEX BY
VARCHAR2(30);
TYPE t_nrstud IS TABLE OF NUMBER INDEX BY
BINARY_INTEGER;
TYPE t_ang IS TABLE OF emp%ROWTYPE INDEX BY
BINARY_INTEGER;
v_varsta t_varsta;
v_nrstud t_nrstud;
v_ang t_ang;
v_numar NUMBER;
BEGIN
v_varsta('Ionescu') := 23;
v_varsta('Badea') := 25;
v_varsta('Avramescu') := 27;
dbms_output.put_line(v_varsta.FIRST); -- Avramescu
dbms_output.put_line(v_varsta.LAST); -- Ionescu
v_nrstud(1211) := 48; -- Indicii nu incep de la
1
v_nrstud(1221) := 29;
v_nrstud(1231) := 20;
v_nrstud(1241) := 21;
v_nrstud(1251) := 17; -- tabloul are doar 5
componente
v_ang(4875).ename := 'BERG';
v_ang(3456).job
:= 'CLERK';
v_ang(3456).sal
:= 3400; -- tabloul are doua
componente
END;
Metodele
care pot fi folosite pentru colectii (o parte sunt valabile si pentru tablouri
asociative):
EXISTS(n) |
TRUE daca elementul cu indice n
exista (este setat)
|
COUNT |
Numarul de elemente din tablou. |
LIMIT |
Doar pentru VARRAY: numarul maxim de elemente
permis. Pentru celelalte tipuri intoarce NULL. |
FIRST si LAST |
Primul, respectiv ultimul element (se refera la
valorile cheii - tablouri asociative - sau indicelui). |
PRIOR(n) si NEXT(n) |
Indexul care precede respectiv succede in tablou
elementul cu indice n. Daca nu exista un astfel de element
intoarce NULL. |
EXTEND[(n[,i)]] |
Extinde tabloul cu un element nul, n elemente
nule sau n elemente egale cu elementul de indice i; nu se
aplica la tablouri asociative |
TRIM[(n)] |
Sterge un element, respectiv n
elemente de la sfarsitul tabloului - nu se aplica la tablouri asociative |
DELETE[(n[,k)]] |
DELETE: sterge toate elementele tabloului. DELETE(n) sterge elementul n DELETE(n, k) sterge toate elementele din plaja n
. . k Nu se aplica la VARRAY. Se foloseste TRIM. |
Exemplu
de folosire a metodelor pentru un tablou asociativ:
DECLARE
TYPE t_nrstud IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE t_ang IS TABLE OF emp%ROWTYPE INDEX BY
BINARY_INTEGER;
v_nrstud
t_nrstud;
v_ang
t_ang;
BEGIN
v_nrstud(1211) := 48; -- Indicii nu incep de la 1
v_nrstud(1221) := 29;
v_nrstud(1231) := 20;
v_nrstud(1241) := 21;
v_nrstud(1251) := 17;
-- tabloul are doar 5
componente
dbms_output.put_line('FIRST: ' || v_nrstud.FIRST); -- afiseaza 1211
dbms_output.put_line('LAST: '||v_nrstud.LAST); -- afiseaza 1251
dbms_output.put_line('COUNT: '||v_nrstud.COUNT); -- afiseaza 5
if v_nrstud.EXISTS(1200) then
dbms_output.put_line('Exista cheia 1200');
else
dbms_output.put_line('Nu exista cheia 1200'); -- nu exista
end if;
if v_nrstud.EXISTS(1231) then
dbms_output.put_line('Exista cheia 1231'); -- exista
else
dbms_output.put_line('Nu
exista cheia 1231');
end if;
dbms_output.put_line('LIMIT: '||v_nrstud.LIMIT); -- doar la VARRAY
dbms_output.put_line('PRIOR(1241):
'||v_nrstud.PRIOR(1241)); -- 1231
dbms_output.put_line('PRIOR(1211):
'||v_nrstud.PRIOR(1211)); -- NULL
dbms_output.put_line('NEXT(1241):
'||v_nrstud.NEXT(1241)); -- 1251
dbms_output.put_line('NEXT(1251):
'||v_nrstud.NEXT(1251)); -- NULL
v_nrstud.DELETE(1);
-- cheia nu exista
dbms_output.put_line('Stergere element cu cheia 1. Raman:'
||v_nrstud.COUNT|| ' elemente');
-- 5
v_nrstud.DELETE(1241);
-- cheie existenta
dbms_output.put_line('Au ramas: '||v_nrstud.COUNT|| '
elemente');--4
v_nrstud.DELETE(1220, 1300); -- existenta chei in plaja data
dbms_output.put_line('Au ramas: '||v_nrstud.COUNT|| '
elemente');--1
v_ang(4875).ename := 'BERG';
v_ang(3456).job
:= 'CLERK';
v_ang(3456).sal
:= 3400; -- 2 chei distincte
dbms_output.put_line('COUNT: '||v_ang.COUNT); -- afiseaza 2
END;
/