6.    Tipuri de date compuse

 

6.1.          Definirea unui tip de date

 

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.

 

6.2.         Inregistrari (RECORD)

 

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;

 

6.3.         Tablouri asociative (TABLE . . . INDEX BY)

 

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;

/