Sunteți pe pagina 1din 37

Capitolul 2.

Limbajul SQL

2.1. 2.2. 2.3. 2.4.

Generalitati Comenzi DML (Data Manipulation Language) Comenzi DDL (Data Definition Language) Limbajul PL/SQL (Oracle)

Page 1 of 37

2.1. Generalitati

Locul SQL in familia limbajelor relationale In abordarea relationala, toate informatiile din baza de date (entitati si legaturi) sunt reprezentate uniform, ca tabele. Reprezentarea uniforma a datelor nu este insa suficienta. Din punctul de vedere al utilizarii datelor, este necesara punerea la dispozitie a unui limbaj de manipulare a datelor, adica a unui set de operatori care sa asigure manipularea datelor reprezentate in forma relationala. Observatii: 1. Uniformitatea reprezentarii datelor conduce la uniformitate la nivelul setului de operatori. Deoarece informatia este reprezentata intr-un singur fel, este necesar un singur operator pentru implementarea fiecarei functii de baza (inserare, stergere, actualizare, regasire). 2. In general, cererile de acces la date trebuie sa trateze seturi de inregistrari, deci sunt necesari operatori capabili sa manipuleze seturi de date. Rezultatul unei cereri de interogare este tot o relatie derivata intr-un anume fel din relatiile deja existente in baza. Cu alte cuvinte, procesul de interogare poate fi privit ca un proces de construire a unei relatii (sau a unei tabele). Deci, se poate defini un set de operatori elementari de construire a unei tabele, pentru implementarea operatiei de interogare. Acesti operatori (SELECT operatorul de selectie, PROJECT operatorul de proiectie si JOIN operatorul de asociere), impreuna cu altii (operatorii traditionali din teoria multimilor: UNION - reuniunea, INTERSECT - intersectia, MINUS diferenta, Produsul cartezian), constituie algebra relationala. Fiecare operatie din algebra relationala are ca operanzi una sau doua relatii si ca rezultat o noua relatie. Algebra relationala constituie un exemplu de limbaj de manipulare a datelor, care pune la dispozitie un set complet de operatori, pentru implementarea operatiei de interogare. Unele sisteme relationale ofera limbaje de manipulare a datelor care au la baza chiar algebra relationala. Exista, totusi, si alte limbaje care opereaza cu relatii, cel putin la fel de puternice ca algebra relationala: ALPHA si QUEL bazate pe calculul relational, SQUARE si SEQUEL (limbajul SQL de mai tirziu) bazate pe operatia de mapping, QBE si CUPID - limbaje grafice. Algebra relationala reprezinta un sistem de referinta in masurarea puterii de selectivitate a celorlalte limbaje relationale. Limbajul SQL (Structured Query Language) Generalitatea limbajului este comparabila cu cea a algebrei relationale, adica operatorii lucreaza cu seturi de date si nu include referiri la caile de acces (limbaj declarativ). Avantaje ale SQL Simplitatea cererile de acces la date pot fi mai usor si mai concis exprimate, in SQL, comparativ cu limbajele de nivel scazut, conducind la imbunatatirea performantelor (pentru cel care dezvolta si pentru cei care intretin aplicatia) Completitudinea limbajul este complet din punct de vedere relational in sensul ca orice relatie derivabila din relatiile deja existente (pe baza unei expresii a calculului relational) poate fi obtinuta utilizind acest limbaj. Puterea limbajului SQL consta, de fapt, in usurinta cu care este obtinuta completitudinea. Orice relatie derivabila poate fi obtinuta utilizind o singura instructiune a limbajului. De fapt, termenul de completitudine d.p.d.v. relational subintelege adeseori faptul ca orice relatie derivabila se poate obtine printr-o singura instructiune. Din punctul de vedere a utilizatorului, completitudinea relationala inseamna ca, daca informatia cautata este in baza, ea poate fi obtinuta printr-o singura cerere. In limbajele de nivel scazut, utilizatorul trebuie sa construiasca proceduri adesea complicate pentru a raspunde unor astfel de cereri. Non-proceduralitatea o instructiune prin care se executa o cerere de acces la date specifica numai care sunt datele solicitate, nu si modul in care se ajunge la ele. O astfel de

Page 2 of 37

instructiune este mai curind o formulare de intentie din partea utilizatorului, ceea ce inseamna ca implementarea este capabila sa capteze intentia acestuia. Captarea intentiei face ca optimizarea cautarii sa devina o problema de natura practica a sistemului si nu o preocupare a utilizatorului. Independenta datelor instructiunile de manipulare a datelor din SQL nu contin referinte la caile explicite de acces la date, cum ar fi indecsii sau secventele fizice. Astfel, SQL asigura o totala independenta fizica a datelor, adica independenta fata de modul de stocare fizica a acestora. SQL asigura intr-o oarecare masura si independenta logica a datelor, adica independenta fata de modul de structurare logica a datelor. Acest nivel de independenta este asigurat prin separarea nivelului extern de cel conceptual, prin mecanismul de viewuri. Tipuri de modificari care pot surveni la nivel conceptual: Adaugarea de noi relatii (tabele) in baza de date sau adaugarea unei noi coloane (atribut) la o tabela (relatie) deja existenta duce la modificarea schemei conceptuale a bazei de date si cu toate acestea nu are efect asupra view-urilor deja existente in baza; view-urile izoleaza utilizatorul fata de aceste modificari Restructurarea schemei conceptuale (a unei tabele) poate fi uneori necesara, in sensul ca informatia stocata in baza ramine aceeasi si se modifica doar amplasarea ei, adica alocarea coloanelor la tabele. Exemplu: inlocuirea unei tabele date prin doua proiectii ale sale. Tabela originala poate fi reconstituita prin executia unei operatii de JOIN asupra celor doua proiectii. Orice operatie de interogare pe view-ul astfel construit este echivalenta interogarii pe tabela initiala. Extensibilitatea facilitatile de interogare oferite de limbajul de baza pot fi extinse prin noi functii Suport pentru limbaje de nivel mai inalt.

Locul SQL in arhitectura sistemelor de baze de date Arhitectura oricarui sistem de baze de date se compune din trei nivele generale: nivelul intern nivelul extern nivelul conceptual reprezentind nivelul de stocare fizica a datelor nivel constind in mai multe reprezentari abstractizate ale unor parti ale bazei date (imagini externe, individuale) nivel intermediar constind intr-o singura reprezentare abstractizata a bazei de date, in totalitatea ei (imagine conceptuala)

Page 3 of 37

Intr-un sistem relational de baze de date, elementele reprezentative pentru fiecare nivel al arhitecturii sunt indicate in figura de mai jos: USER

SQL

Vederea 1
Nivel extern

Vederea 2

Tabela 1
Nivel conceptual Nivel intern

Tabela 2

Tabela 3

Fisier 1

Fisier 2

Fisier 3

Observatii: Tabela este un obiect cu existenta independenta de a altora, spre deosebire de vederi (view-uri) care sunt obtinute pe baza altor tabele sau view-uri Echivalentul tabelei la nivel fizic este fisierul. Un utilizator poate avea acces la tabele sau view-uri prin intermediul limbajului SQL care include o componenta de definire a datelor (DDL) si o componenta de manipulare a datelor (DML). DML opereaza atit asupra obiectelor nivelului extern cit si asupra obiectelor nivelului conceptual. DDL poate fi utilizat pentru definirea obiectelor la nivel extern (view-uri), la nivel conceptual (tabele) si chiar la nivel fizic (indecsi). In unele implementari (Oracle), SQL pune la dispozitie si facilitati de control asupra datelor, care nu pot fi clasificate ca apartinind unei din componentele DDL si DML. Un exemplu de astfel de facilitate il constituie instructiunea GRANT care permite acordarea drepturilor de acces la obiectele bazei de date.

Page 4 of 37

2.2. Comenzi DML


2.2.1. Interogari intructiunea SELECT Operatia fundamentala in SQL este maparea reprezentata sintactic ca un bloc SELECT-FROM-WHERE. Ex: O cerere de interogare de tipul regaseste toate unitatile judetui Alba se reprezinta astfel: SELECT sirues, den FROM nomun WHERE cjud=1 Operatia de mapare consta intr-o selectie orizontala (toate unitatile judetului Alba), urmata de o selectie verticala (cod sirues si denumire). In termenii algebrei relationale, operatia se poate descompune in secventa de operatori selectie-proiectie.

1) Interogare simpla
SELECT sirues FROM nomun

regaseste codurile unitatilor din nomenclator

In acest exemplu, maparea SELECT-FROM-WHERE se compune dintr-o selectie orizontala, urmata de o proiectie. Subsetul obtinut prin selectia orizontala este chiar tabela initiala, in absenta filtrului din clauza WHERE. Operatorul clasic de proiectie din algebra relationala extrage coloanele specificate, eliminind totodata inregistrarile duble, redondante din coloanele extrase (rezultatul proiectiei este tot o relatie). SQL nu elimina, in general, duplicatele din rezultatul unui SELECT daca userul nu o cere in mod explicit prin calificatorul DISTINCT, astfel: SELECT DISTINCT sirues FROM nomun

2) (tot o) Interogare simpla


SELECT * FROM nomun

regaseste toate caracteristicile unitatilor din nomenclator

Rezultatul obtinut este o copie a tabelei; * reprezinta prescurtarea listei ordonate a tuturor numelor de cimpuri, asa cum apar in dictionarul sistemului de baze de date. 3) Interogare calificata regaseste codurile sirues ale unitatilor din judetul Alba a caror forma de proprietate are codul 30

SELECT sirues FROM nomun WHERE cjud=1 and cformp=30 Conditia sau predicatul care urmeaza dupa clauza WHERE poate include operatori de comparare: =, <>, <, <=, >, >=, operatori booleeni AND, OR, NOT sau paranteze, pentru a indica ordinea de evaluare.

4) Interogare cu ordonare regaseste codurile sirues ale unitatilor si cifra de afaceri corespunzatoare, in ordinea descrescatoare a cifrei de afaceri pe anul 1998
SELECT sirues, val FROM dat WHERE codi=CA27 and an=1998 ORDER BY val DESC

Page 5 of 37

In general, instructiunea SELECT nu garanteaza regasirea inregistrarilor intr-o anumita ordine. Prin clauza ORDER BY, userul poate solicita ordonarea inregistrarilor. 5) Interogare pe mai multe tabele regaseste codul, denumirea si cifra de afaceri a unitatilor, in ordinea descrescatoare a cifrei de afaceri pe anul 1998 SELECT nomun.sirues, den, val FROM nomun, dat WHERE nomun.an=dat.an AND nomun.sirues=dat.sirues AND codi=CA27 AND an=1998 ORDER BY val DESC Acest exemplu arata modul in care este implementat operatorul algebric JOIN in limbajul SQL. Utilizatorul poate indica mai multe tabele in clauza FROM si poate folosi numele tabelelor drept calificatori in clauzele SELECT si WHERE pentru a rezolva ambiguitatile, acolo unde este cazul. Instructiunea SELECT din exemplu opereaza astfel: Se formeaza produsul cartezian dintre NOMUN si DAT Inregistrarile care nu satisfac conditia de JOIN sunt eliminate din relatia rezultata Coloanele sirues, den si val sunt extrase prin proiectie din setul rezultat la pasul anterior. Tipuri de JOIN Equi-join: conditia de JOIN se bazeaza pe egalitatea dintre valorile coloanei comune (coloanele care participa la conditia de JOIN au acelasi domeniu de valori Non-equi-join: conditia de join se bazeaza pe oricare alt operator in afara celui de egalitate (<, >, ) Outer-join: forteaza aparitia tuturor inregistrarilor unei tabele care participa la o operatie de equi-join Auto-join: operatia de JOIN se efectueaza pe aceeasi tabela

6) Interogare cu non-equi-join
de salariati,

regaseste grupa de salariati dupa indicatorul numar mediu

pentru fiecare unitate, in anul 1998 SELECT sirues, val, grupa FROM dat, grsal WHERE an=1998 AND codi=NMS32 AND val>=min AND val<=max Interogarea este un exemplu de non-equi-join pentru ca nici o coloana din tabela DAT nu are corespondent in tabela GRSAL, adica nu exista doua coloane in DAT si respectiv GRSAL cu acelasi domeniu de valori. 7) Interogare cu outer-join regaseste formele de proprietate din nomenclatorul de unitati care au sau nu reprezentare in nomenclatorul NOMFP SELECT nomun.cformp, nomfp.den FROM nomfp, nomun WHERE nomfp.cformp(+)=nomun.cformp AND an=1998 Operatorul (+) se plaseaza de partea tabelei care este deficienta in informatii (NOMFP). Acest operator determina crearea uneia sau a mai multor inregistrari cu valori nule care sa participe la realizarea conditiei de equi-join. Instructiunea SELECT din exemplu opereaza astfel: pentru fiecare inregistrare din NOMUN care nu se gaseste in NOMFP se creeaza o inregistrare cu valori nule in NOMFP. se executa operatia clasica de equi-join pe tabelele astfel imbogatite.

Page 6 of 37

8) Interogare cu auto-join regaseste toate perechile grupa-clasa caen pentru grupele 501si
502 SELECT grupe.ccaen, grupe.den, clase.ccaen, clase.den FROM nomcaen grupe, nomcaen clase WHERE grupe.ccaen=clase.csup AND (grupe.ccaen=501 OR grupe.ccaen=502) Acest exemplu implica JOIN-ul unei tabele cu ea insasi; conditia de JOIN consta in faptul ca o clase CAEN are ca superior o grupa CAEN. Tabela NOMCAEN apare de doua ori in clauza FROM. Pentru a distinge intre cele doua aparitii, se introduc nume arbitrare (alias-uri) GRUPE, CLASE care sunt utilizate in clauzele SELECT si WHERE drept calificatori. 9) Interogare folosind operatorul ANY regaseste numele unitatilor care desfasoara activitatea cu codul CAEN 1010, pentru indicatorul cifra de afaceri Limbajul SQL pune la dispozitie mai multe metode de tratare a acestei interogari: Utilizind operatorul JOIN instructiunea se scrie astfel: SELECT DISTINCT den FROM nomun, dat WHRE nomun.an=dat.an AND nomun.sirues=dat.sirues codv=1010 AND codi=CA27B AND

Observatie: calificatorul DISTINCT este necesar pentru eliminarea inregistrarilor duble din JOIN. Interogarea extrage inregistrari dintr-o singura tabela NOMUN, cu toate ca ambele tabele trebuie inspectate pentru a produce rezultatul dorit. Deci, acelasi rezultat se poate obtine daca rescriem interogarea astfel: SELECT DISTINCTden FROM nomun WHERE conditie_asupra_DAT unde: conditie_asupra_DAT reprezinta conditia pe care o unitate trebuie sa o indeplineasca pentru a fi selectata, adica sa aiba date pentru activitatea 1010. Aceasta conditie poate fi exprimata astfel: SELECT DISTINCT den FROM nomun WHERE (an, sirues)=ANY(SELECT an, sirues FROM dat WHERE codi=CA27B AND codv=1010) Conditia: f=ANY() se evalueaza la TRUE daca si numai daca f este egal cu cel putin una dintre valorile care rezultata in urma evaluarii operatiei din subquery. Similar, f<ANY() se evalueaza la TRUE daca si numai daca f este mai mic decit cel putin una dintre valorile rezultate in urma evaluarii din sub-query.

10) Interogare folosind <ANY regaseste codurile sirues ale unitatilor cu cifra de afaceri mai mica decit valoarea maxima a cifrei de afaceri, pentru indicatorul CA27, in anul 1998 SELECT sirues FROM dat WHERE an=1998 AND codi=CA27 AND val<ANY(SELECT val FROM dat WHERE an=1998 AND codi=CA27) Clauza WHERE specifica faptul ca valoarea cifrei de afaceri trebuie sa fie mai mica decit cel putin una din valorile cifrei de afaceri pe anul 1998 si nu faptul ca trebuie sa fie mai mica decit orice valoare a cifrei de afaceri pe anul 1998. Forma =ANY poate fi inlocuita prin operatorul IN astfel: 11) Interogare folosind operatorul IN regaseste numele unitatilor care desfasoara activitatea cu codul CAEN 1010, pentru indicatorul cifra de afaceri (vezi exemplul 9)

Page 7 of 37

SELECT den FROM nomun WHERE (an, sirues) IN (SELECT an, sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=1010) AND an=1998 Observatie: operatorii =ANY si IN sunt complet interschimbabili (implementeaza operatorul de apartenenta din teoria multimilor). 12) Interogare cu multiple nivele de imbricare regaseste numele unitatilor care desfasoara cel putin o activitate de industrie in anul 1998 SELECT den FROM nomun WHERE an=1998 AND (an, sirues) IN (SELECT an, sirues FROM dat WHERE an=1998 AND codv IN (SELECT ccaen FROM nomcaen WHERE csup>=101 AND csup<=410)) Observatie: interogarile pot avea oricite nivele de imbricare. 13) Interogari corelate (interogari folosind referinte intre blocuri) regaseste numele unitatilor care desfasoara activitate cu codul CAEN 1010 in anul 1998 (vezi exemplele 9 si 11) SELECT den FROM nomun WHERE 1010 IN (SELECT codv FROM dat WHERE (an, sirues)=(nomun.an, nomun.sirues)) AND an=1998 Referintele necalificate an, sirues sunt implicit calificate de numele tabelei DAT din blocul curent. Pentru rezolvarea ambiguitatilor, referirea la nomun.an si nomun.sirues apartinind blocului exterior se face prin folosirea calificatorului nomun. 14) Interogari folosind sub-query cu aceeasi tabela in ambele blocuri regaseste numele unitatilor care au aceeasi forma de proprietate cu unitatea cu codul SIRUES 10110116 SELECT DISTINCT sirues, den FROM nomun WHERE cformp IN (SELECT cformp FROM nomun WHERE sirues=10110116) 15) Interogari corelate cu aceeasi tabela in ambele blocuri SELECT DISTINCT sirues FROM nomun n1 WHERE sirues IN (SELECT sirues FROM nomun n2 WHERE n1.an<>n2.an) unde: n1, n2 sunt nume arbitrare (alias-uri) care leaga referinta n2.an din blocul interior la referinta n2.an din blocul exterior 16) Interogare folosind operatorul ALL regaseste numele unitatilor care nu desfasoara activitate cu codul CAEN 1010 in anul 1998 SELECT den FROM nomun WHERE sirues<>ALL(SELECT sirues FROM dat WHERE dat.an=nomun.an AND codv=1010) AND an=1998 Operatorul *ALL unde * poate fi <, <=, >, >=, =, <> se defineste astfel: regaseste toate unitatile urmarite in cel putin doi ani

Page 8 of 37

Conditia f * ALL (SELECT) se evalueaza la TRUE daca si numai daca comparatia f*v se evalueaza la TRUE oricare ar fi valoarea v din setul rezultat prin executia (SELECT). f<>ALL (SELECT) este echivalent cu f NOT IN (SELECT). Atunci cind un sub-query returneaza o singura inregistrare, operatorii =ANY, >ALL, pot fi abreviati prin =, >, ca in exemplul de mai jos. 17) Interogare folosind forma prescurtata pentru =ANY regaseste toate unitatile care au aceeasi forma de proprietate cu unitatea 10110116, in anul 1998 (vezi exemplul 14) SELECT sirues FROM nomun WHERE an=1998 AND cformp=(SELECT cformp FROM nomun WHERE an=1998 AND sirues=10110116) Observatie: pentru a putea folosi operatorul =, sub-query-ul trebuie sa aduca o singura inregistrare. 18) Interogare folosind operatorul EXISTS regaseste numele unitatilor care desfasoara activitatea cu codul CAEN 1010 in anul 1998 (vezi exemplul 9, 11, 13)

SELECT den FROM nomun WHERE EXISTS (SELECT * FROM dat WHERE dat.an=nomun.an AND dat.sirues=nomun.sirues AND codv=1010) AND an=1998 EXISTS reprezinta cuantificatorul existential. Expresia EXISTS (SELECT ) se evaleaza la TRUE daca si numai daca rezultatul evaluarii (SELECT ) este nevid, adica daca si numai daca exista cel putin o inregistrare in tabela DAT care satisface conditia din clauza WHERE a expresiei (SELECT). 19) Interogare folosind operatorul NOT EXISTS regaseste numele unitatilor care nu desfasoara activitate cu cod 1010 in anul 1998 (vezi exemplul 16) SELECT den FROM nomun WHERE NOT EXISTS (SELECT * FROM dat WHERE dat.an=nomun.an AND dat.sirues=nomun.sirues AND codv=1010) AND an=1998 Sau: regaseste unitatile urmarite in toti anii anchetei SELECT * FROM nomun a WHERE NOT EXISTS (SELECT DISTINCT an FROM nomun b WHERE NOT EXISTS (SELECT * FROM nomun c WHERE c.an=b.an AND c.sirues=a.sirues)) 20) Interogare folosind UNION regaseste toate unitatile care au activitate principala cu codul 1010 sau desfasoara activitate cu codul 1010, pentru indicatorul cifra de afaceri, in anul 1998 SELECT sirues FROM nomun WHERE an=1998 AND ccaen=1010 UNION SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=1010

Page 9 of 37

Observatie: UNION este operatorul traditional de reuniune din teria multimilor. A UNION B, unde A, B-multimi, este multimea elementelor care apartin fie multimii A, fie multimii B, fie ambelor. Duplicatele redondante sunt intotdeauna eliminate din rezultatul unui UNION. In unele implementari ale SQL, utilizarea calificatorului ALL face ca rezultatul operatiei UNION sa contina si duplicatele, astfel: SELECT sirues FROM nomun WHERE an=1998 AND ccaen=1010 UNION ALL SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=1010 21) Interogari cu valori calculate unitati regaseste grupele caen asociate claselor din nomenclator de

SELECT DISTINCT ccaen clasa, ccaen/10 grupa FROM nomun ORDER BY clasa, grupa Clauzele SELECT, WHERE, ORDER BY ale unei interogari pot contine expresii aritmetice. 22) Interogari cu valori NULL regaseste sectiunile si sub-sectiunile din nomenclatorul CAEN

SELECT ccaen, den FROM nomcaen WHERE csup IS NULL UNION SELECT ccaen, den FROM nomcaen WHERE csup IN (SELECT ccaen, den FROM nomcaen WHERE csup IS NULL) Atunci cind o valoare NULL (valoare lipsa) este comparata cu o alta valoare in evaluarea unui predicat, indiferent de operatorul de comparare implicat, rezultatul compararii nu este niciodata TRUE, chiar daca cealalta valoare este deasemenea NULL. Astfel, nici unul din predicatele de mai jos nu este adevarat: NULL>5 NULL<5 NULL=5 NULL<>5 NULL=NULL Predicatele sunt evaluate folosind trei valori logice: adevarat, fals si necunoscut. Clauzele WHERE identifica inregistrarile pentru care predicatul se evalueaza la TRUE si, deci, nu se evalueaza la FALSE sau UNKNOWN. Limbajul SQL pune la dispozitie un predicat special de forma f IS NULL pentru stabilirea valorii de NULL a unei coloane (sau expresie).

Functii de grup Desi complet relational, un limbaj limitat la facilitatile prezentate nu poate raspunde la orice cerere de interogare. Cererea: identifica numarul unitatilor care fac parte din esantion in anul 1998 nu poate fi solutionata prin metodele exemplificate mai sus. De aceea, limbajul SQL pune la dispozitie un set de functii speciale (COUNT, SUM, AVG, MAX, MIN) numite functii de grup. Aceste functii opereaza asupra unei colectii de valori dintr-o coloana a unei tabele, cu exceptia functiei COUNT(*), si produc urmatoarele rezultate: COUNT numar de valori SUM suma valorilor AVG media aritmetica a valorilor MIN valoarea ce mai mica

Page 10 of 37

MAX valoarea cea mai mare. Pentru SUM si AVG, coloana pe care se aplica functia trebuie sa contina valori numerice. In general, argumentul unei functii poate fi precedat de calificatorul DISTINCT specificind eliminarea valorilor duble inaintea aplicarii functiei de grup. Valorile nule in argument sunt intotdeauna eliminate inainte de aplicarea functiei de grup, cu exceptia cazului COUNT(*) care numara toate inregistrarile chiar daca valorile tuturor cimpurilor sunt null. Daca multimea valorilor pe care se aplica functia este vida, COUNT returneaza valoarea 0, iar celelalte functii returneaza NULL. Exemple 23) Utilizarea functiei COUNT regaseste numarul pozitiilor din nomenclatorul CAEN

SELECT COUNT(*) FROM nomcaen SELECT COUNT(ccaen) FROM nomcaen SELECT COUNT(csup) FROM nomcaen Primele doua exemple identifica in mod corect numarul inregistrarilor din nomenclator, spre deosebire de ultimul care identifica de fapt numarul pozitiilor care au valori nenule pentru codul superior (csup).

24) Utilizarea functiei MAX regaseste codurile unitatilor care au cifra de afaceri mai mica decit valoarea maxima a cifrei de afaceri, pentru indicatorul CA27, in anul 1998 (vezi exemplul 10) SELECT sirues FROM dat WHERE codi=CA27 AND an=1998 and val<(SELECT MAX(val) FROM dat WHERE an=1998 and codi=CA27) 25) Utilizarea clauzei GROUP BY regaseste valoarea totala a cifrei de afaceri pe ani

SELECT an, SUM(val) val_tot FROM dat GROUP BY an Operatorul GROUP BY regrupeaza (si ordoneaza) inregistrarile tabelei in grupe corespunzatoare valorilor coloanei (coloanelor) pe care se aplica. Functiile de grup din clauza SELECT care insotesc operatorul GROUP BY se aplica la nivelul fiecarui grup. 26) Utilizarea clauzei HAVING regaseste toate unitatile cu activitatea principala 1010, urmarite in cel putin doi ani SELECT sirues FROM nomun WHERE ccaen=1010 GROUP BY sirues HAVING COUNT(sirues)>1 Clauzele FROM, WHERE, GROUP BY si HAVING se aplica in ordinea sugerata de exemplu, astfel: FROM creeaza o copie a tabelei nomun WHERE elimina inregistrarile care nu satisfac conditia ccaen=1010 GROUP BY inregistrarile ramase sunt grupate dupa sirues HAVING sunt eliminate grupurile care nu satisfac conditia COUNT(sirues)>1 SELECT sunt extrase codurile sirues ale unitatilor din grupurile ramase.

Page 11 of 37

27) Utilizarea functiilor de grup cu JOIN calculeaza totalul cifrei de afaceri pe an si activitate principala, pentru activitatile de industrie desfasurate de acele unitati care sunt observate in cel putin 2 ani SELECT nomun.an, ccaen, SUM(val) FROM nomun, dat WHERE nomun.an=dat.an AND nomun.sirues=dat.sirues AND codi=CA27 AND (ccaen=1010 OR ccaen=1130) GROUP BY nomun.an, ccaen HAVING COUNT(nomun.sirues)>1 ORDER BY 1,3 DESC

Particularitati ale implementarilor limbajului SQL in sistemele Oracle si Visual FoxPro a. Operatori pe seturi de inregistrari Operatori INTERSECT MINUS (diferenta) Oracle Visual FoxPro

Oracle implementeaza operatiile de intersectie si diferenta din teoria multimilor, prin extinderea limbajului SQL cu operatorii INTERSECT si MINUS. Exemple: Utilizarea operatorului INTERSECT regaseste unitatile cu activitate principala 1010, care desfasoara activitatea cu codul CAEN 5111, in anul 1998 SELECT sirues FROM nomun WHERE an=1998 AND ccaen=1010 INTERSECT SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=5111 In absenta operatorului INTERSECT, in Visual FoxPro, cererea de mai sus poate fi formulata astfel: SELECT sirues FROM nomun WHERE an=1998 AND ccaen=1010 AND sirues IN (SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=5111) Utilizarea operatorului MINUS regaseste unitatile cu activitate principala 1010, care nu desfasoara activitatea cu codul CAEN 5111, in anul 1998

SELECT sirues FROM nomun WHERE an=1998 AND ccaen=1010 MINUS SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=5111 In absenta operatorului MINUS, in Visual FoxPro, cererea de mai sus poate fi formulata astfel: SELECT sirues FROM nomun

Page 12 of 37

WHERE an=1998 AND ccaen=1010 AND sirues NOT IN (SELECT sirues FROM dat WHERE an=1998 AND codi=CA27B AND codv=5111)

b. Functii uzuale pentru date si conversii de date Functii/operatori Apartenenta unei valori la un interval Apartenenta unei valori la o lista Cautarea unei valori dupa un sablon Testare valori nule Conversia unei valori nule intr-o alta valoare Schimbarea caracterelor majuscule in caractere mici Schimbarea caracterelor mici in majuscule Schimbarea primei litere din fiecare cuvint in majuscule Concatenarea a doua siruri de caractere Completare la stinga a unui sir de caractere cu n aparitii ale unui alt caracter Completare la dreapta a unui sir de caractere cu n aparitii ale unui alt caracter Completare la stinga si la dreapta a unui sir de caractere cu n aparitii ale unui alt caracter Extragerea unui subsir dintr-un sir de caractere Cautarea unui subsir intr-un sir de caractere Eliminarea aparitiilor unui caracter de la stinga unui sir de caractere Eliminarea aparitiilor unui caracter de la dreapta unui sir de caractere Eliminarea aparitiilor unui caracter de la stinga si de la dreapta unui sir de caractere Calculul lungimii unui sir de caractere Translatarea unui sir de caractere Inlocuirea unui subsir dintr-un sir de caractere cu un alt subsir Rotunjirea / trunchierea unei valori numerice Calculul valorii absolute Calculul restului impartirii Conversia unei valori de tip numar sau data la un sir de caractere Oracle x BETWEEN x1 AND x2 x IN (x1,x2,) x LIKE s% x IS NULL NVL(x,y) LOWER(x) UPPER(x) INITCAP(x) CONCAT(x1,x2) sau x1||x2 LPAD(x,n,c) RPAD(x,n,c) Visual FoxPro BETWEEN(x,x1,x2) INLIST(x,x1,x2,) x LIKE s% ISNULL(x) NVL(x,y) LOWER(x) UPPER(x) PROPER(x) x1+x2 PADL(x,n,c) PADR(x,n,c) PADC(x,n,c) SUBSTR(x,poz,n) INSTR(x,y,poz,n) LTRIM(x,c) RTRIM(x,c) SUBSTR(x,poz,n) AT(x,y,n) sau RAT(x,y,n) LTRIM(x) pentru c= RTRIM(x) pentru c= ALLTRIM(x) LENGTH(x) TRANSLATE(x,y1,y2) REPLACE(x,y1,y2) ROUND(x,n) TRUNC(x,n) ABS(x) MOD(x,y) TO_CHAR(x,fmt) LEN(x) CHRTRAN(x,y1,y2) STRTRAN(x,y1,y2,ns,n) ROUND(x,n) ABS(x) MOD(x,y) x%y STR(x,n) pentru x numeric DTOC(x,1) pentru x de tip data

Page 13 of 37

Conversia unui sir de caractere intr-un numar Conversia unui sir de caractere intr-o valoare de tip data Conversia conditionala

TO_NUMBER(x) TO_DATE(x,fmt) DECODE(x, x1,y1,x2,y2, ,d)

VAL(x) CTOD(x) IIF(cond,x,y)

Exemple: b1. Utilizarea operatorului LIKE regaseste unitatile care contin in denumire cuvintul <societate> SELECT den FROM nomun WHERE LOWER(den) LIKE %societate% Sau: SELECT den FROM nomun WHERE INSTR(LOWER(den), societate)<>0 b2. Utilizarea operatorului BETWEEN regaseste unitatile care au activitatea principala de industrie"

SELECT DISTINCT sirues, ccaen FROM nomun WHERE ccaen BETWEEN 1010 AND 4102 b3. Utilizarea functiei DECODE calculeaza totalul cifrei de afaceri pentru formele de proprietate 31 si 32 SELECT nomun.an, SUM(DECODE(cformp,31,val,0)) ca_31, SUM(DECODE(cformp,32,val,0)) ca_32 FROM nomun, dat WHERE nomun.an=dat.an AND nomun.sirues=dat.sirues AND codi=CA27 AND cformp IN (31,32) GROUP BY nomun.an b4. Utilizarea functiei LENGTH regaseste toate grupele din nomenclatorul CAEN SELECT ccaen, den FROM nomcaen WHERE LENGTH(ccaen)=3

c.

Interogari ierarhice Pentru interogarea tabelelor care contin date organizate ierarhic (NOMCAEN), implementarea limbajului SQL in Oracle faciliteaza selectarea inregistrarilor in ordine ierarhica prin utilizarea urmatoarelor clauze: START WITH CONNECT BY WHERE specifica punctul de plecare al cautarii in arbore specifica relatia intre parinte si descendenti in sensul parcurgerii arborelui restringe numarul inregistrarilor returnate fara a afecta alte inregistrari.

ORACLE utilizeaza informatiile din clauzele de mai sus pentru formarea arborelui, astfel: - Identifica inregistrarile care vor fi folosite ca radacini in parcurgerea arborelui; clauza START WITH specifica conditia pe care trebuie sa o indeplineasca o inregistrare pentru a fi considerata radacina. In absenta acestei clauze, toate inregistrarile din tabela sunt considerate radacini. Conditia poate contine si un sub-query.

Page 14 of 37

- Identifica inregistrarile descendentilor pentru fiecare inregistrare radacina. Fiecare inregistrare descendent trebuie sa satisfaca conditia din clauza CONNECT BY, in raport cu una din inregistrarile radacina. Clauza CONNECT BY nu poate contine subquery. - Identifica generatii succesive de descendenti, adica, pentru fiecare descendent selectat in iteratia anterioara, identifica descendentii prin evaluarea conditiei din clauza CONNECT BY in raport cu parintele curent. - Restringe numarul inregistrarilor selectate prin aplicarea filtrului din clauza WHERE. Filtrul se aplica pentru fiecare inregistrare in parte, fara eliminarea descendentilor in cazul in care este eliminat parintele. Clauza CONNECT BY specifica legatura intre inregistrarile parinte si inregistrarile fiu intr-o interogare ierarhica. Clauza CONNECT BY poate contine conditii multiple reunite prin operatori logici. Una din conditiile clauzei trebuie sa utilizeze operatorul PRIOR pentru a indica inregistrarea parinte si poate avea una din formele: PRIOR expresie1 operator_comparatie expresie2 Expresie1 operator_comparatie PRIOR expresie2. Pentru identificare descendentilor inregistrarii parinte, ORACLE evalueaza expresia PRIOR pentru inregistrarea parinte si cealalta expresie pentru fiecare inregistrare din tabela. Inregistrarile care satisfac conditia reprezinta descendentii parintelui. Clauza CONNECT BY poate contine si alte conditii care actioneaza ca filtru asupra inregistrarilor selectate. Exemplu: Clauza CONNECT BY PRIOR ccaen=csup defineste legatura ierarhica potrivit careia valoarea CCAEN a inregistrarii parinte este egala cu valoarea CSUP a inregistrarii fiu. Pseudo-coloana LEVEL Intructiunile SELECT care executa interogari ierarhice pot utiliza pseudo-coloana LEVEL. LEVEL returneaza valoarea 1 pentru inregistrarea radacina, 2 pentru inregistrarile fiu ale inregistrarii radacina, samd.

Exemple: a. regaseste lista sectiunilor cu toti descendentii din nomenclatorului NOMCAEN SELECT LPAD( ,2*(LEVEL-1)) || ccaen || LPAD(den, LENGTH(den)+3) caen FROM nomcaen CONNECT BY PRIOR ccaen=csup START WITH csup IS NULL b. regaseste structura ierarhica a nomenclatorului NOMCAEN SELECT LPAD( ,2*(LEVEL-1)) || ccaen || LPAD(den, LENGTH(den)+3) caen FROM nomcaen CONNECT BY PRIOR ccaen=csup START WITH csup IS NULL AND ccaen>0

2.2.2. Instructiuni DML pentru manipularea datelor Limbajul SQL DML pune la dispozitie trei operatii de modificare a datelor:

Page 15 of 37

UPDATE (modificare) Forma generala: UPDATE nume_tabela SET col [col,]={expresie, subcerere} [WHERE conditie]

INSERT (inserare) Forma generala: INSERT INTO nume_tabela [(col [, col] )] VALUES (val [, val] ) INSERT INTO nume_tabela [(col [,col] )] SELECT lista FROM tabela [, tabela]

DELETE (stergere) Forma generala: DELETE FROM nume_tabela [WHERE conditie]

a) Actualizarea unei singure inregistrari

modifica denumirea unitatiii cu codul 10110116 pe anul 1998

UPDATE nomun SET den=INITCAP(LOWER(den)) WHERE sirues=10110116 AND an=1998 In clauza SET orice referinta la o coloana din membrul drept al egalitatii ia in considerare valoarea coloanei dinaintea modificarii. b) Actualizarea unui set de inregistrari modifica denumire formelor de proprietate eliminind spatiile din stinga

UPDATE nomfp SET den=LTRIM(den, ) c) Actualizarea inregistrarilor folosind sub-query actualizeaza activitatile principale din nomenclatorul de unitati, dupa codul CAEN corespunzator cifrei de afaceri maxime a unitatii 10110116 UPDATE nomun SET ccaen=(SELECT codv FROM dat a WHERE codi=CA27B AND a.an=nomun.an AND a.sirues=nomun.sirues AND val>=ALL(SELECT val FROM dat b WHERE b.an=a.an AND b.sirues=a.sirues AND b.codi=a.codi)) WHERE an=1998 AND sirues=10110116 Observatii: nu pot fi actualizate coloanele care compun cheia primara la actualizarea unei coloane care participa la o cheia straina se verifica in mod automat apartenenta acestei valori la domeniul coloanei corespunzatoare din tabela parinte referita in constringerea de integritate. d) Inserarea unei inregistrari de adauga o inregistrare noua in tabela temporara a formelor

Page 16 of 37

proprietate INSERT INTO temp_nomfp VALUES(10, Proprietate publica) e) Inserarea unui set de inregistrari adauga inregistrarile din tabela formelor de proprietate in tabela temporara a formelor de proprietate INSERT INTO temp_nomfp SELECT cformp, den FROM nomfp WHERE cformp NOT IN (SELECT cformp FROM temp_nomfp) Observatie: La inserarea unei inregistrari se verifica restrictiile de domeniu, NOT NULL, unicitate si cele legate de integritatea referentiala.

f)

Stergerea unei inregistrari sterge inregistrarea cu forma de proprietate 10 din tabela TEMP_NOMFP DELETE temp_nomfp WHERE cformp=10

g) Stergerea unui set de inregistrari TEMP_NOMFP DELETE temp_nomfp

sterge

toate

inregistrarile

din

tabela

Page 17 of 37

2.3. Comenzi DDL


Instructiuni DDL pentru creare, modificare si stergere tabele Tabela este un obiect (persistent) cu existenta independenta de a altor obiecte ale bazei de date. Ea poate fi reprezentata la nivel fizic printr-un fisier de stocare. O tabela poate fi creata in orice moment prin executia instructiunii DDL CREATE TABLE, cu urmatoarea sintaxa: CREATE TABLE nume_tabela (definitie_coloana [, definitie_coloana]) [restrictii_integritate_tabela] [informatii_stocare_tabela] unde definitie_coloana este de forma: nume_coloana tip_date [DEFAULT valoare] [restrictii_integritate_coloana] Prin executia instructiunii CREATE TABLE, o noua tabela este creata in baza de date pe baza specificatiilor legate de coloane, restrictii de integritate si spatiu de stocare. Exemplu: CREATE TABLE dat ( sirues number(9), codi varchar2(10), codv number(4), an number(4) DEFAULT 1998, val number(14)); Optiunea DEFAULT permite preintimpinarea aparitiei valorilor de NULL sau aparitia erorilor la executia unei instructiuni INSERT pentru care a fost omisa valoarea unei coloane (in exemplu an). Instructiunea CREATE TABLE permite specificarea reestrictiilor de integritate la nivelul coloanelor sau la nivelul tabelelor. Tipuri de restrictii: Restrictia NOT NULL Sintaxa: [CONSTRAINT nume_restrictie] NOT NULL Exemplu: CREATE TABLE dat ( sirues number(9) NOT NULL, codi varchar2(10) NOT NULL, codv number(4), an number(4) DEFAULT 1998 NOT NULL, val number(14)); sau CREATE TABLE dat ( sirues number(9) CONSTRAINT nn_dat_sirues NOT NULL, codi varchar2(10) NOT NULL, codv number(4),

Page 18 of 37

an number(4) DEFAULT 1998 NOT NULL, val number(14)); Observatie: Fiecare restrictie este descrisa si memorata in dictionarul bazei de date. Utilizatorul poate asocia un nume fiecarei restrictii prin clauza CONSTRAINT; in absenta acestei clauze sistemul atribuie un nume implicit de forma SYS_Cn. Restrictia de unicitate Forma generala: La nivelul tabelei Exemplu: CREATE TABLE dat ( sirues number(9) NOT NULL, codi varchar2(10) NOT NULL, codv number(4), an number(4) DEFAULT 1998 NOT NULL, val number(14), constraint uk_dat unique (an, sirues, codi, codv)) La nivelul coloanei Exemplu: CREATE TABLE temp ( cformp number NOT NULL CONSTRAINT uk_cformp UNIQUE, den varchar2(100)) Restrictia de cheie primara (impusa de integritatea entitatilor) Forma generala: La nivelul tabelei Exemplu: CREATE TABLE nomun ( an number(4), sirues number(9), den varchar2(100) constraint nn_nomun_den not null, cformp number(2), ccaen varchar2(4), cjud number(2), constraint pk_nomun primary key (an, sirues)) La nivelul coloanei Exemplu: CREATE TABLE temp ( cformp number NOT NULL CONSTRAINT pk_cformp PRIMARY KEY, den varchar2(100)) [CONSTRAINT nume_restrictie] PRIMARY KEY [CONSTRAINT nume_restrictie] PRIMARY KEY (coloana [, coloana]) [CONSTRAINT nume_restrictie] UNIQUE [CONSTRAINT nume_restrictie] UNIQUE (coloana [, coloana])

Page 19 of 37

Prin specificarea unei restrictii de cheie primara, se creeaza un index unic pentru tabela respectiva si se atasaza in mod implicit restrictii de NOT NULL tuturor coloanelor referite in specificatia de cheie primara.

Restrictii de integritate referentiala (definirea cheilor straine) Forma generala: La nivelul tabelei [CONSTRAINT nume_restrictie] FOREIGN KEY (coloana [, coloana]) REFERENCES nume_tabela (coloana [, coloana]) [CONSTRAINT nume_restrictie] FOREIGN KEY REFERENCES nume_tabela (coloana)

La nivelul coloanei Exemplu:

CREATE TABLE dat ( sirues number(9) NOT NULL, codi varchar2(10) constraint fk_dat_codi references nomind(codi), codv number(4) NOT NULL, an number(4) NOT NULL, val number(14), constraint fk_dat_an_sirues foreign key (an, sirues) references nomun(an, sirues), constraint uk_dat unique (an, sirues, codi, codv)) Restrictii de domeniu Forma generala: [CONSTRAINT nume_restrictie] CHECK conditie [DISABLE] Observatie: conditia unei restrictii de domeniu nu admite sub-cereri si referiri la pseudocoloane Exemplu: CREATE TABLE nomjud ( cjud number(2) constraint pk_nomjud primary key, den varchar2(25), fsor number(2) constraint ck_nomjud_jud check fsor between 1 and 42) Crearea unei tabele pe baza altei tabele Forma generala: CREATE TABLE nume_tabela [(nume_coloana [, nume_coloana])] AS SELECT instructiune_select Observatie: daca in instructiunea CREATE TABLE sunt specificate coloanele, atunci numarul lor trebuie sa fie acelasi cu numarul coloanelor rezultate din clauza SELECT. Noua tabela va contine datele regasite de instructiunea SELECT. Singura restrictie care se importa este NOT NULL. Exemplu: CREATE TABLE temp AS SELECT * FROM nomfp;

Page 20 of 37

Modificarea definitiei une tabele instructiunea ALTER TABLE Forme: ALTER TABLE nume_tabela ADD | MODIFY (definitie_coloana [, definitie_coloana]) ALTER TABLE nume_tabela ADD (restrictie_integritate_tabela [, restrictie_integritate_tabela]) ALTER TABLE nume_tabela DROP {PRIMARY KEY | UNIQUE (coloana [, coloana]) | CONSTRAINT nume_restrictie} ALTER TABLE nume_tabela { ENABLE | DISABLE } {PRIMARY KEY | UNIQUE (coloana [, coloana]) | CONSTRAINT nume_restrictie} Observatii: Nu se poate asocia restrictia NOT NULL unei coloane care contine deja valori nule. Pentru adaugarea unei coloane cu restrictia NOT NULL, se executa secventa: - se adauga coloana fara restrictia de NOT NULL - se completeaza cu valori - se adauga restrictia NOT NULL. Nu se poate micsora dimensiunea unei coloane si nu I se poate schimba tipul de date decit daca este golita in prealabil. Nu se poate utiliza clauza MODIFY pentru a defini o restrictie pe o coloana, cu exceptia celor de tip NULL/NOT NULL. Exemplu: ALTER TABLE nomfp DISABLE CONSTRAINT pk_nomfp; Stergerea unei tabele instructiunea DROP Sintaxa: DROP TABLE nume_tabela [CASCADE CONSTRAINT]

Instructiuni DDL pentru creare si stergere view-uri View-ul este o fereastra prin care datele din tabele pot fi vizualizate si chiar modificate. Un view se baseaza pe una sau mai multe tabele sau pe un alt view care la rindul lui se bazeaza pe date reale stocate intr-o tabela. Crearea unui view este rezultatul unei instructiuni SELECT. View-ul este o tabela virtuala (nu este stocata fizic), deci nu are date proprii ci prelucreaza date reale din alte tabele. View-ul poate fi folosit pentru a vizualiza date din mai multe tabele, dupa cum view-uri diferite pot vizualiza in moduri diferite un acelasi set de date. Sintaxa: CREATE [OR REPLACE] [FORCE] VIEW nume_view [(coloana [, coloana])] AS SELECT [WITH CHECK OPTION [CONSTRAINT nume_restrictie]] Observatii: Optiunea OR REPLACE se utilizeaza atunci cind exista deja un view cu acelasi nume, iar view-ul care se creeaza il va inlocui pe cel vechi.

Page 21 of 37

Optiunea FORCE determina crearea view-ului chiar daca tabela de baza nu exista inca. La executia view-ului, tabela trebuie, totusi, sa existe. La operatiile INSERT si UPDATE pe view-uri, optiunea WITH CHECK OPTION impune controlul restrictiilor si validarea datelor, in sensul ca se pot adauga sau modifica numai inregistrarile din tabela selectate prin view. O data executata, comanda CREATE VIEW nu determina executia instructiunii SELECT ci doar stocarea acesteia in dictionarul de date. La accesarea datelor prin view, Oracle executa urmatoarele operatii: cauta definitia view-ului in dictionarul de date verifica privilegiile de acces transforma cererea specificata de view in operatiile echivalente (regasire date, actualizare) pe tabela bazei. Se poate executa modificarea datelor (INSERT, DELETE, UPDATE) cu ajutorul view-urilor daca definitia view-ului indeplineste urmatoarele conditii: nu contine operatia JOIN nu contine functii de grup nu contine clauzele GROUP BY, DISTINCT nu se foloseste variabila ROWNUM nu exista coloane definite prin expresii, pentru UPDATE. Stergere view-uri Sintaxa: DROP VIEW nume_view;

Instructiuni DDL pentru creare si stergere indecsi Indecsii sunt structuri arborescente care permit cresterea vitezei de acces la datele unei tabele si, eventual, impunerea unei restrictii de unicitate pe coloanele unei tabele (in cazul indecsilor unici). Tipuri de indecsi: index unic (UNIQUE) asigura unicitatea valorilor din coloanele specificate index ne-unic (NONUNIQUE).

Sintaxa instructiunii CREATE INDEX: CREATE [UNIQUE] INDEX nume_index ON nume_tabela (coloana [, coloana] ); Sintaxa instructiunii DROP INDEX: DROP INDEX nume_index;

Page 22 of 37

2.4.

Limbajul PL/SQL
Caracteristici.Avantaje Suport pentru tipuri de date SQL si tipuri de date specifice Structuri de control Cursoare Tratarea erorilor Subprograme si pachete de subprograme

Caracteristici. Avantaje PL/SQL (Procedural Language/SQL) este extensia procedurala a limbajului SQL in Oracle. Acest limbaj incorporeaza multe din caracteristicile din limbajele de programare clasice permitind includerea instructiunilor SQL de interogare si manipulare a datelor in unitati de cod procedurale, structurate pe blocuri. Caracteristici: Limbaj structurat Blocul logic constituie unitatea elementara (proceduri, functii, blocuri anonime) ale unui program PL/SQL si poate contine un numar nelimitat de sub-blocuri imbricate. Un bloc PL/SQL are trei parti componente: declarativa executabila de tratare a erorilor.

Forma generala a blocului PL/SQL: [DECLARE declaratii] BEGIN instructiuni [EXCEPTION instructiuni de tratare a erorilor] END; PL/SQL permite declararea variabilelor si a constantelor in sectiunea declarativa a blocului si utilizarea acestora in instructiunile SQL si procedurale care compun celelalte doua sectiuni.Situatiile de eroare numite exceptii pot fi tratate (interceptate) in sectiunea EXCEPTION a blocului PL/SQL. Suport pentru limbajul SQL PL/SQL permite utilizarea tuturor instructiunilor SQL de manipulare a datelor, controlul cursoarelor si controlul tranzactional, precum si a tuturor functiilor, operatorilor si pseudo coloanelor disponibile in limbajului SQL al sistemului de baze de date ORACLE. Variabilele si tipurile de date ale PL/SQL sunt compatiblile cu cele ale limbajului SQL si cu definitiile stocate in tabelele de dictionar ale bazei de date. Exemplu: declararea variabilei v_ccaen pe baza definitiei coloanei ccaen din nomun DECLARE v_ccaen BEGIN END; nomun.ccaen%TYPE

Page 23 of 37

permite stabilirea dinamica (la momentul executiei) a tipului de date pentru variabila v_ccaen, adica aceasta va avea acelasi tip de date ca si coloana ccaen independent de modificarea ulterioara a acesteia. Aceasta facilitate asigura independenta datelor, reduce costurile de intretinere si permite adaptarea automata a programelor la modificarile de structura ale bazei de date. Limbajul PL/SQL poate fi utilizat atit la nivelul serverului ORACLE prin proceduri stocate, triggere si pachete de subprograme cit si in instrumentele de dezvoltare specifice ORACLE (Sql*Plus, Forms, Reports). Controlul fluxului de prelucrare Se pot folosi instructiuni de: control conditional control iterativ IF THEN ELSE FOR LOOP END LOOP

pentru controlul fluxului de executie. Portabilitatea Aplicatiile scrise in limbajul PL/SQL sint portabile pe orice sistem de operare si orice platforma pe care ruleaza ORACLE. Imbunatatirea performantelor Aplicatiile care nu utilizeaza blocuri PL/SQL lanseaza la un moment dat o singura cerere SQL catre serverul ORACLE generind trafic si timp de executie suplimentar. Aplicatiile care grupeaza mai multe instructiuni SQL in blocuri logice lanseaza o singura data intregul set de instructiuni reducind comunicatia cu serverul ORACLE si imbunatatind performantele. Suport pentru tipuri de date SQL si tipuri de date specifice Orice constanta sau variabila are un tip de data asociat, care specifica formatul de stocare, constringerile si domeniul de valabilitate a valorilor. PL/SQL pune la dispozitie o mare varietate de tipuri de date scalare si compuse predefinite sau definite de utilizator. Tipul de date scalar nu are componente interne si poate stoca valori de tip numeric, caracter, data/timp sau booleene. Exemple de tipuri scalare predefinite in PL/SQL: BINARY_INTEGER FLOAT INTEGER NUMBER LONG VARCHAR2 DATE BOOLEAN PL/SQL ofera posibilitatea de a introduce subtipuri de date scalare definite de utilizator: SUBTYPE nume_sub_tip IS tip_de_baza unde nume_sub_tip este specificatorul subtipului iar tip_de_baza poate avea una din urmatoarele forme: nume_tip_scalar nume_tabela%ROWTYPE nume_tabela.nume_coloana%TYPE nume_variabila%TYPE

Page 24 of 37

nume_cursor%ROWTYPE nume_tabela_plsql%TYPE nume_variabila_tip_inregistrare%ROWTYPE

Exemple: DECLARE SUBTYPE sir SUBTYPE tip_caen SUBTYPE rec_caen TYPE grupa_tip SUBTYPE grsal_tip CURSOR c_fp SUBTYPE rec_fp BEGIN END; IS VARCHAR2; IS nomcaen.ccaen%TYPE; IS nomcaen%ROWTYPE; IS RECORD(val_min INTEGER, val_max INTEGER); IS grupa_tip; IS SELECT * FROM nomfp; IS c_fp%ROWTYPE

Un tip de date compus are componente interne care pot fi manipulate individual. PL/SQL pune la dispozitie doua tipuri de date compuse definite de utilizator: table si record care pot stoca colectii de date. Tabele PL/SQL Obiectele de tipul table se numesc tabele PL/SQL (vectori) si sint modelate ca tabelele bazei de date desi nu reprezinta acelasi lucru. Tabelele PL/SQL sint colectii ordonate de elemente de acelasi tip, similar vectorilor din alte limbaje de programare. Fiecare element are un index unic care specifica pozitia sa in colectia de elemente. Numarul elementelor unei tabele PL/SQL este nelimitat iar indexul acesteia nu trebuie sa aiba valori consecutive. De exemplu, pot fi utilizate codurile formelor de proprietate (10, 20, 31...) pentru indexarea tabelei PL/SQL a formelor de proprietate. Tabelele PL/SQL permit stocarea unor seturi de valori si transmiterea acestora ca parametri procedurilor stocate. Definirea tabelelor PL/SQL se realizeaza in doi pasi: definirea tipului table in partea declarativa a unui bloc, subprogram sau package folosind sintaxa: TYPE nume_tip_table IS TABLE OF tip_date [NOT NULL] INDEX BY BiNARY_INTEGER unde nume_tip_table este specificatorul de tip iar tip_date este specificatorul de tip pentru elementele tabelei (orice tip de date scalar CHAR, DATE, NUMBER sau tipuri de date inregistrare cu cimpuri scalare). Clauza INDEX BY trebuie sa contina in mod obligatoriu tipul de date BINARY_INTEGER. declararea tabelei PL/SQL in sectiunea declarativa a unui bloc PL/SQL DECLARE TYPE tip_den_nomfp IS TABLE OF nomfp.den%TYPE INDEX BY BINARY_INTEGER; TYPE tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; t_den_nomfp tip_den_nomfp; t_nomfp tip_nomfp; BEGIN END; Utilizarea tabelelor PL/SQL 1. Pentru a accesa un element al tabelei PL/SQL se foloseste sintaxa :

nume_tabela_plsql(index)

Page 25 of 37

unde index este o variabila avind tipul de date BINARY_INTEGER. Exemple: t_den_nomfp(20) set_denfp(t_den_nomfp(i)) refera elementul cu indexul 20 si nu al 20-lea element din tabela apel de procedura care refera elementul i al tabelei

2. Este posibila asignarea unei tabele PL/SQL la o alta tabela PL/SQL numai daca cele doua tabele au la baza acelasi tip de data Exemple: DECLARE TYPE tip_den_nomfp IS TABLE OF nomfp.den%TYPE INDEX BY BINARY_INTEGER; TYPE tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; TYPE temp_tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; t_den_nomfp tip_den_nomfp; t_nomfp tip_nomfp; t_temp_nomfp temp_tip_nomfp; BEGIN t_den_nomfp:=t_nomfp; -- instructiune ilegala, tabelele au tipuri de -- baza diferita t_temp_nomfp:=t_nomfp -- instructiune permisa END; 3. Pentru a accesa un element al unei tabele PL/SQL de inregistrari se foloseste sintaxa: nume_tabela_plsql(index).nume_cimp Exemplu: DECLARE TYPE tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; t_nomfp tip_nomfp; BEGIN IF t_nomfp(10).cformp=10 THEN END; 4. Utilizarea atributelor PL/SQL: atributele EXISTS, COUNT, FIRST, LAST, NEXT, PRIOR, DELETE faciliteaza accesarea si actualizarea tabelelor PL/SQL. Exemplu: DECLARE TYPE tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; t_nomfp tip_nomfp; index BINARY_INTEGER; BEGIN IF t_nomfp.EXISTS(1) THEN FOR index IN 1.. t_nomfp.COUNT LOOP.. FOR index IN t_nomfp.FIRST..t_nomfp.LAST LOOP.. index:=t_nomfp.FIRST;

Page 26 of 37

WHILE index IS NOT NULL LOOP . index:=t_nomfp.NEXT(index); . t_nomfp.DELETE(3); t_nomfp.DELETE(4, 7); t_nomfp.DELETE; END; Observatii: EXISTS(n) se evalueaza la true daca exista elementul cu indexul n. Acest atribut se utilizeaza pentru a evita eroarea NO_DATA_FOUND care este generata de referirea unui element inexistent. COUNT returneaza numarul de elemente dintr-o tabela PL/SQL. FIRST si LAST returneaza cel mai mic si respectiv cel mai mare index al tabelei PL/SQL. Daca tabela PL/SQL este goala FIRST si LAST returneaza null. PRIOR si NEXT permit navigarea prin tabela PL/SQL. PRIOR(n) returneaza indexul elementului (sau null daca acesta nu exista) care precede elementul cu indexul n din tabela PL/SQL NEXT(n) returneaza indexul elementului care urmeaza dupa elementul cu indexul n din tabela PL/SQL. DELETE sterge toate elementele tabelei; DELETE(n) sterge elementul cu indexul n; DELETE(m, n) sterge toate elementele cu index intre m si n. 5. Utilizarea tabelelor PL/SQL in instructiuni SQL

Elementele unei tabele PL/SQL pot fi referite in instructiune SQL de manipulare a datelor: Exemplu: DECLARE TYPE tip_nomfp IS TABLE OF nomfp%ROWTYPE INDEX BY BINARY_INTEGER; t_nomfp tip_nomfp; index BINARY_INTEGER; BEGIN SELECT * INTO t_nomfp(1) FROM nomfp WHERE cform=10; .. FOR index IN 1.. t_nomfp.COUNT LOOP INSERT INTO nomfp (cformp,den) VALUES (t_nomfp(index).cformp, t_nomfp(index).den) . INSERT INTO nomfp VALUES (t_nomfp(index)) -- instructiune ilegala END; Tipul de date record Obiectele avind tipul de date record se numesc structuri de tip inregistrare si contin unul sau mai multe cimpuri care pot avea tipuri de date diferite. Definirea unei structuri de tip inregistrare se realizeaza doi pasi: definirea tipului record in partea declarativa a unui bloc, subprogram sau package folosind sintaxa: TYPE nume_tip_record IS RECORD (cimp, [, cimp]); unde nume_tip_record este numele specificatorului de tip iar cimp poate avea urmatoarea sintaxa: nume_cimp tip_date [[NOT NULL] [:= | DEFAULT] expresie]

Page 27 of 37

declararea structurii de tip inregistare pe baza tipului record definita mai sus:

Exemplu: DECLARE TYPE tip_rec_nomfp TYPE tip_rec_unit nomfp_rec temp_nomfp_rec unitate_rec BEGIN END; IS RECORD (cod INTEGER, nume VARCHAR2(20) ); IS RECORD (cod nomun.sirues%TYPE, formap tip_rec_nomfp); tip_rec_nomfp; tip_rec_nomfp tip_rec_unit;

Utilizarea structurilor de tip inregistrare Pentru a accesa un cimp al unei structuri de tip inregistrare se foloseste sintaxa: nume_inregistrare.nume_cimp Exemplu: DECLARE TYPE tip_rec_nomfp TYPE tip_rec_unit nomfp_rec temp_nomfp_rec BEGIN nomfp_rec.nume:=UPPER(nomfp_rec.nume); temp_nomfp_rec:=nomfp_rec; SELECT cformp, den INTO temp_nomfp_rec FROM nomfp WHERE cformp=10; INSERT INTO nomfp VALUES (temp_nomfp_rec); -- instructiune ilegala END; Structuri de control Limbajul PL/SQL permite urmatoarele tipuri de instructiuni de control IS RECORD (cod INTEGER, nume VARCHAR2(20) ); IS RECORD (cod nomun.sirues%TYPE, formap tip_rec_nomfp); tip_rec_nomfp; tip_rec_nomfp;

1. Control conditional:
Instructiunea IF: sintaxa generala IF conditie1 THEN secventa_instructiuni1; [ELSIF conditie2 THEN secventa_instructiuni2;] [ELSE secventa_instructiuni3;] END IF

2. Control iterativ:
Instructiunea LOOP: forme permise LOOP secventa_instructiuni; . [EXIT | EXIT WHEN conditie]; -- pentru iesirea din bucla
Page 28 of 37

END LOOP sau WHILE conditie LOOP secventa_instructiuni; END LOOP; sau FOR contor IN [REVERSE] limita_inferioara.. limita_superioara LOOP secventa_instructiuni; END LOOP

3. Control secvential:
Instructiunea GOTO: sintaxa GOTO eticheta Instructiunea NULL Cursoare Oracle utilizeaza zone de lucru pentru executia instructiunilor SQL si memorarea informatiilor legate de executie. Cursorul PL/SQL permite referirea acestei zone de lucru si accesul la informatia pe care contine. Exista doua tipuri de cursoare implicit si explicit. Limbajul PL/SQL declara in mod implicit un cursor pentru fiecare instructiune SQL de manipulare a datelor inclusiv pentru interogarile care au ca rezultat o singura inregistrare. Pentru interogarile care returneaza mai multe inregistrari se poate declara un cursor explicit pentru procesarea individuala a inregistrarilor. Sintaxa generala pentru declararea unui cursor explicit: CURSOR nume_cursor [(parametru [, parametru])] IS instructiune_select unde parametru are sintaxa: nume_parametru [ IN ] tip_date [(:= | DEFAULT) expresie] Exemplu: DECLARE CURSOR c_nomfp IS SELECT * FROM nomfp; Utilizarea cursoarelor PL/SQL OPEN-FETCH-CLOSE Pentru utilizarea cursoarelor, PL/SQL pune la dispozitie trei comenzi: OPEN, FETCH, CLOSE. Dupa initializarea cursorului, prin instructiunea OPEN care identifica setul de inregistrari, se utilizeaza instructiunea FETCH pentru a regasi prima inregistrare. Executia repetata a instructiunii FETCH permite regasirea celorlalte inregistrari ale cursorului. Dupa procesarea ultimei inregistrari cursorul este eliberat prin instructiunea CLOSE. -- eticheta este marcata prin <<nume_eticheta>> -- transfera controlul la instructiunea urmatoare

Page 29 of 37

Exemplu: DECLARE CURSOR c_nomfp IS SELECT * FROM nomfp; rec_nomfp c_nomfp%ROWTYPE; BEGIN OPEN c_nomfp ; LOOP FETCH c_nomfp INTO rec_nomfp; EXIT WHEN c_nomfp%NOTFOUND -- testeaza sfirsitul setului de inregistrari . END LOOP; CLOSE c_nomfp; END; Observatie: In locul constructiei OPEN FETCH CLOSE se poate folosi instructiunea de control iterativ FOR - LOOP. DECLARE CURSOR c_nomfp IS SELECT * FROM nomfp; rec_nomfp c_nomfp%ROWTYPE; BEGIN FOR c_rec IN c_nomfp LOOP rec_nomfp:=c_rec END LOOP; END; Instructiunea FOR-LOOP declara in mod implicit contorul c_rec ca o variabila de tipul c_nomfp %ROWTYPE, deschide cursorul, parcurge toate inregistrarile prin variabila c_rec si inchide cursorul dupa ce toate inregistrarile au fost procesate. (alt) Exemplu: DECLARE CURSOR c_nomun (cod_fp, INTEGER) IS SELECT * FROM nomun where cformp=cod_fp; BEGIN FOR unit_rec IN c_nomun(10) LOOP END LOOP; END; Utilizarea atributelor unui cursor Atributele %FOUND, %ISOPEN, %NOFOUND si %ROWCOUNT asociate unui cursor furnizeaza informatii utile legate de excutia unei instructiuni de manipulare a datelor.Atributele asociate cursoarelor pot fi utilizate in instructiuni procedurale dar nu pot fi utilizate in instructiuni SQL. Exemplu: DECLARE CURSOR c_nomfp IS SELECT * FROM nomfp; rec_nomfp c_nomfp%ROWTYPE; BEGIN OPEN c_nomfp; LOOP FETCH c_nomfp INTO rec_nomfp; IF (c_nomfp%FOUND) AND (c_nomfp%ROWCOUNT>5) THEN . END IF; EXIT WHEN c_nomfp%NOTFOUND; -- testeaza sfirsitul setului de inregistrari

Page 30 of 37

.. END LOOP; IF c_nomfp%ISOPEN THEN CLOSE(c_nomfp); END IF; END; Observatii: Atributul %FOUND se evalueaza la true daca ultima instructiune FETCH executata a adus o inregistrare. Daca este utilizata inainte de executia primului FETCH, dar dupa deschiderea cursorului, %FOUND se evalueaza la NULL. Daca se evalueaza inainte de deschiderea cursorului, %FOUND genereaza eroarea predefinita INVALID_CURSOR. Atributul %ISOPEN se evalueaza la true daca cursorul caruia ii este asociat este deschis. Atributul %ROWCOUNT desemneaza numarul de inregistrari aduse prin FETCH pina la momentul evaluarii. Daca este evaluat inainte de prima executie a instructiunii FETCH, dar dupa deschiderea cursorului, atributul %ROWCOUNT returneaza 0. Daca cursorul caruia i se asociaza nu este deschis, evaluarea atributului %ROWCOUNT produce eroarea INVALID_CURSOR. Aceleasi atribute pot fi asociate si cursoarelor implicit, returnind informatii despre executia celei mai recente instructiuni INSERT, UPDATE, DELETE sau SELECT INTO.

Tratarea erorilor In limbajul PL/SQL o conditie de eroare poarta denumirea de exceptie. Exceptiile pot fi predefinite (ZERO_DEVIDE, NO_DATA_FOUND) sau definite de utilizator in partea declarativa a oricarui bloc PL/SQL anonim, subprogram sau pachet de subprograme. Atunci cind se produce o eroare, se genereaza o exceptie, executia normala a programului este oprita, iar controlul este transferat sectiunii de tratare a erorilor din blocul PL/SQL. Exceptiile predefinite sint generate automat de catre sistem. Exceptiile definite de utilizator trebuie generate in mod explicit prin instructiuni RAISE (care pot genera si erori predefinite). De exemplu se poate defini exceptia cod_incorect pentru a trata cazul introducerii unui cod sirues care nu apartine nomenclatorului. DECLARE cod_incorect EXCEPTION; PRAGMA EXCEPTION_INIT (cod_incorect, -2291); BEGIN INSERT INTO dat (an, sirues, codi, codv) VALUES (1998, 2541, CA27B, 1010 ); EXCEPTION WHEN cod_incorect THEN RAISE_APPLICATION_ERROR (-20000, Cod sirues incorect); END; La introducerea unui cod incorect intr-o coloana care are asociata o restrictie de integritate referentiala, Oracle genereaza eroarea cu codul 2291. Prin introducerea exceptiei cod_incorect, eroarea este interceptata, iar programul intoarce codul si mesajul definite de utilizator. Exceptii predefinite: Nume exceptie predefinita CURSOR_ALREADY_OPEN DUP_VAL_ON_INDEX INVALID_CURSOR INVALID_NUMBER LOGIN_DENIED Cod ORA-06511 ORA-00001 ORA-01001 ORA-01722 ORA-01017 Semnificatie Deschiderea unui cursor deja deschis Inserare valori duble intr-o coloana cu cheie unica Operatie ilegala pe cursor (inchiderea unui cursor nedeschis) Conversia unui sir de caractere care nu reprezinta un numar valid la o valoare numerica Conectarea cu nume utilizator/parola invalida

Page 31 of 37

NO_DATA_FOUND NOT_LOGGED_ON TOO_MANY_ROWS VALUE_ERROR ZERO_DIVIDE

ORA-01403 ORA-01012 ORA-01422 ORA-06502 ORA-01476

Executia unei instructiuni SELECT INTO nu returneaza nici o inregistrare Executia unei instructiuni in absenta conectarii la Oracle Executia unei instructiuni SELECT INTO returneaza mai mult de o inregistrare Operatii aritmetice, conversii invalide Impartire la zero

Forma generala a sectiunii de tratare a erorilor. EXCEPTION WHEN nume_exceptie [OR nume_exceptie] THEN instructiuni_executabile Exemplu: EXCEPTION WHEN NO_DATA_FOUND THEN instructiuni_executabile1; WHEN cod_incorect THEN instructiuni_executabile2; WHEN OTHERS THEN instructiuni_executabile3; END; Observatie: daca eroarea care apare in timpul executiei este regasita in sectiunea de tratare a exceptiilor, se executa setul de instructiuni corespunzator. Altfel, se executa instructiunile prevazute de clauza WHEN OTHERS, daca aceasta exista. Daca lipseste programul se intrerupe si se obtine codul de eroare generat de sistem. Propagarea si domeniul de valabilitate a exceptiilor La generarea unei exceptii daca PL/SQL nu gaseste o instructiune de tratare a acesteia in blocul curent, exceptia se propaga, adica se reproduce in blocurile superioare succesive pina cind este identificata o instructiune de tratare sau sint epuizate blocurile superioare.

Exceptia A este tratata local, in blocul interior, in care se produce; dupa tratarea exceptiei A executia continua in blocul superior.

Page 32 of 37

Exceptia B nu are sectiune de tratare asociata in blocul in care se produce (blocul interior), de aceea se propaga in blocurile superioare. Propagarea inceteaza atunci cind fie este gasita o sectiune de tratare a exceptiei B, fie nu mai exista blocuri superioare.

Exceptia C nu are sectiune de tratare asociata, in nici unul din blocurile PL/SQL. De aceea, se produce o exceptie netratabila iar controlul este transferat mediului gazda (apelant). Exemplu: calculul ponderii cifrei de afaceri pentru cod CAEN 1010 in totalul cifrei de afaceri pentru unitatile judetului Alba DECLARE CURSOR c_sirues (p_jud NUMBER) IS SELECT sirues FROM nomun where an=1998 and cjud=p_jud; cod_unitate nomun.sirues%TYPE; cod_eroare number; mesaj_eroare varchar2(50); pondere number(14,3); BEGIN OPEN c_sirues(1); LOOP FETCH c_sirues INTO cod_unitate; EXIT WHEN c_sirues%NOTFOUND; BEGIN SELECT (NVL(a.val,0)/NVL(b.val,0))*100 FROM dat a, dat b INTO pondere WHERE a.an=b.an and a.sirues=b.sirues and a.codi=CA27B and b.codi=CA27 and a.codv=1010

Page 33 of 37

and a.an=1998 and a.sirues=cod_unitate; EXCEPTION WHEN NO_DATA_FOUND OR ZERO_DIVIDE THEN pondere:=null; END; INSERT INTO sum_temp (sirues, pondere) VALUES (cod_unitate, pondere); END LOOP; CLOSE c_sirues; EXCEPTION WHEN OTHERS THEN cod_eroare:=SQLCODE; mesaj_eroare:=SUBSTR(SQLERRM,1,50); IF c_sirues%ISOPEN THEN CLOSE c_sirues; END IF; RAISE_APPLICATION_ERROR(-20000, Eroare de executie ||to_char(SQLCODE)); END;

Programe si pachete de sub-programe Programele sunt blocuri PL/SQL cu nume, care pot fi apelate cu sau fara parametri. Limbajul PL/SQL pune la dispozitie doua feluri de sub-programe: proceduri si functii. Procedurile sunt folosite, in general, pentru a realiza o actiune, iar functiile pentru calculul valorilor. Sub-programe Sub-programele pot fi definite de orice instrument Oracle care suporta limbajul PL/SQL. Sub-programele se compun din trei sectiuni: declarativa, executabila si de tratare a erorilor. Sectiunea declarativa contine declaratiile de tipuri, cursoare, constante, variabile, exceptii si sub-programe imbricate. Aceste obiecte sunt locale sub-programului si isi inceteaza existenta la parasirea lui. Sectiunea executabila contine instructiuni de atribuire, controlul executiei si instructiuni SQL de manipulare a datelor. Sectiunea de tratare a exceptiilor contine instructiuni care servesc la rezolvarea situatiilor de eroare. Avantajele utilizarii sub-programelor sunt modularitatea si reutilizabilitatea. Tipuri de sub-programe: Proceduri Sintaxa generala: PROCEDURE nume_procedura [(parametru [,parametru ])] IS [declaratii_locale] BEGIN instructiuni_executabile [EXCEPTION rutine_tratare_erori] END [nume_procedura]; unde: parametru se va inlocui cu o secventa de tipul nume_variabila [IN | OUT | IN OUT] tip [{ := | DEFAULT } valoare ]

Page 34 of 37

Tipul parametrilor: IN parametru de intrare: permite transferul unui parametru sub-programului apelat. In interiorul sub-programului apelat, acesta se comporta ca o constanta, deci nu i se pot atribui valori OUT parametru de iesire: permite transferul unui parametru sub-programului apelat, pentru a returna o valoare programului apelant. In interiorul sub-programului apelat, parametrul de iesire nu este disponibil decit pentru operatii in care i se atribuie valori. IN OUT parametru de intrare-iesire: se comporta ca o variabila obisnuita. I se pot asigna valori, iar valoarea lui poate fi asigna altei variabile. Exemplu: PROCEDURE pondere_ca (cod_jud nomjud.cjud%TYPE, cod_caen dat.codv%TYPE) IS CURSOR c_sirues (p_jud NUMBER) IS SELECT sirues FROM nomun where an=1998 and cjud=p_jud; cod_unitate nomun.sirues%TYPE; cod_eroare number; mesaj_eroare varchar2(50); pondere number(14,3); BEGIN OPEN c_sirues(cod_jud); LOOP FETCH c_sirues INTO cod_unitate; EXIT WHEN c_sirues%NOTFOUND; BEGIN SELECT (nvl(a.val,0)/nvl(b.val,0))*100 FROM dat a, dat b INTO pondere WHERE a.an=b.an and a.sirues=b.sirues and a.codi=CA27B and b.codi=CA27 and a.codv=cod_caen and a.an=1998 and a.sirues=cod_unitate; EXCEPTION WHEN NO_DATA_FOUND OR ZERO_DIVIDE THEN pondere:=null; END; INSERT INTO sum_temp (sirues, pondere) VALUES (cod_unitate, pondere); END LOOP; CLOSE c_sirues; EXCEPTION WHEN OTHERS THEN cod_eroare:=SQLCODE; mesaj_eroare:=SUBSTR(SQLERRM,1,50); IF c_sirues%ISOPEN THEN CLOSE s_sirues; END IF; RAISE_APPLICATION_ERROR(-20000, Eroare de executie ||to_char(SQLCODE)); END; Procedura poate fi apelata ca o instructiune SQL executabila, astfel: Pondere_ca(1);

Page 35 of 37

Functii Sintaxa generala: FUNCTION nume_functie [(argument [,argument ])] RETURN tip IS [declaratii_locale] BEGIN instructiuni_executabile [EXCEPTION rutine_tratare_erori] END [nume_functie]; unde: argument se va inlocui cu o secventa de tipul nume_variabila [IN | OUT | IN OUT] tip [{ := | DEFAULT } valoare ] Exemplu: FUNCTION calc_pondere (p_an dat.an%TYPE, p_sirues dat.sirues%TYPE, p_caen dat.codv%TYPE) RETURN NUMBER IS pondere number; BEGIN SELECT (nvl(a.val,0)/nvl(b.val,0))*100 FROM dat a, dat b INTO pondere WHERE a.an=b.an and a.sirues=b.sirues and a.codi=CA27B and b.codi=CA27 and a.codv=p_caen and a.an=p_an and a.sirues=p_sirues; RETURN pondere; EXCEPTION WHEN NO_DATA_FOUND OR ZERO_DIVIDE THEN RETURN null; END; Functia calc_pondere este apelata din procedura pondere_ca astfel: PROCEDURE pondere_ca (cod_jud nomjud.cjud%TYPE, cod_caen dat.codv%TYPE) IS CURSOR c_sirues (p_jud NUMBER) IS SELECT sirues FROM nomun where an=1998 and cjud=p_jud; cod_unitate nomun.sirues%TYPE; cod_eroare number; mesaj_eroare varchar2(50); pondere number(14,3); FUNCTION calc_pondere (p_an dat.an%TYPE, p_sirues dat.sirues%TYPE, p_caen dat.codv%TYPE) RETURN NUMBER ; BEGIN OPEN c_sirues(cod_jud); LOOP FETCH c_sirues INTO cod_unitate; EXIT WHEN c_sirues%NOTFOUND; pondere:=calc_pondere(1998, cod_unitate, cod_caen); IF pondere IS NOT NULL THEN INSERT INTO sum_temp (sirues, pondere) VALUES (cod_unitate, pondere); END IF; END LOOP; CLOSE c_sirues; EXCEPTION WHEN OTHERS THEN cod_eroare:=SQLCODE; mesaj_eroare:=SUBSTR(SQLERRM,1,50); IF c_sirues%ISOPEN THEN

Page 36 of 37

CLOSE c_sirues; END IF; RAISE_APPLICATION_ERROR(-20000, Eroare de executie ||to_char(SQLCODE)); END;

Pachete de sub-programe Pachetul reprezinta un obiect al bazei de date, care grupeaza tipuri de date, obiecte si subprograme aflate in legatura logica. Pachetele au doua parti componente: specificatia si corpul. In sectiunea de specificatii, se declara tipurile, variabilele, constantele, exceptiile, cursoarele si subprogramele care compun pachetul. Toate acestea sunt publice, adica disponibile aplicatiilor. In corpul pachetului, se definesc complet cursoarele si sub-programele declarate in sectiunea de specificatii. Spre deosebire de sub-programe, pachetele nu pot fi apelate, parametrizate sau imbricate. Totusi, forma unui pachet este similara cu cea a unui sub-program. Sintaxa generala: PACKAGE nume_pachet IS declaratii de tipuri si obiecte publice declaratii de sub-programe END nume_pachet; PACKAGE BODY nume_pachet IS declaratii de tipuri si obiecte proprii corpurile sub-programelor [BEGIN instructiuni de initializare] -- se executa doar la prima referire a pachetului END; Referirea unui obiect din pachet se face astfel: nume_pachet.nume_obiect Exemple de pachete predefinite: DBMS_OUTPUT DBMS_SQL - ofera proceduri de afisare pe ecran - ofera proceduri de executie a unei intructiuni SQL DDL intr-un subprogram PL/SQL.

Page 37 of 37