11.07.2015 Views

Capitolul IV Limbajul PL/SQL

Capitolul IV Limbajul PL/SQL

Capitolul IV Limbajul PL/SQL

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

57<strong>Capitolul</strong> <strong>IV</strong><strong>Limbajul</strong> <strong>PL</strong>/<strong>SQL</strong>GeneralităŃi<strong>Limbajul</strong> <strong>SQL</strong> (Structured Query Language) este un limbaj declarativorientat pe obŃinerea de mulŃimi de selecŃie într-o aplicaŃie în arhitectură clientserver.EficienŃa sa este remarcabilă dar în cazul în care elementele unei mulŃimide selecŃie trebuie accesate pe rând, nu în grup, utilizarea sa nu mai esteposibilă. Pe de altă parte <strong>SQL</strong> nu oferă nici suportul necesar realizării interfeŃeiunei aplicaŃii. În contrast cu <strong>SQL</strong>, limbajele procedurale pot manipula liniiindividuale dintr-o mulŃime de selecŃie. Ele dispun de funcŃii care permit trecereade la o linie la alta şi ramificarea codului în funcŃie de rezultatul testării valorilorpreluate din tabelele bazei de date.<strong>Limbajul</strong> <strong>PL</strong>/<strong>SQL</strong> (Procedural Language extensions to <strong>SQL</strong>) a fostdezvoltat de compania Oracle ca extensie a limbajului declarativ <strong>SQL</strong>. <strong>PL</strong>/<strong>SQL</strong>este un limbaj de programare procedural care poate fi folosit pentru descriereaunor prelucrări complexe sau pentru programarea unor secvenŃe de cod caretrebuie executate automat la apariŃia unui eveniment (triggere).O caracteristică remarcabilă a limbajului <strong>PL</strong>/<strong>SQL</strong> este faptul căprocedurile sau funcŃiile scrise vor fi memorate în baza de date. Aceleaşiprelucrări pot fi realizate de regulă şi în cadrul aplicaŃiilor client care acceseazădatele din bază, dar în cazul modificării unei metode de calcul trebuie refăcuteaplicaŃiile client afectate şi suportate toate costurile pe care le implicăredistribuirea unor noi versiuni ale aplicaŃiilor client.Având în vedere faptul că de multe ori aplicaŃiile din domeniul bazelor dedate sunt în arhitectură client-server şi aplicaŃia client accesează aplicaŃia server(Oracle XE) prin intermediul unei reŃele, utilizarea pe cât posibil a procedurilorscrise în <strong>PL</strong>/<strong>SQL</strong> poate ameliora semnificativ viteza de prelucrare. În cazul uneiproceduri care ar implica transferul spre aplicaŃia client a unui volum mare dedate (rezultatul unei interogări de exemplu), întârzierile cauzate de reŃeaua princare se accesează serverul de baze de date pot fi mari. Dacă prelucrarea datelornu presupune afişarea acestora în aplicaŃia client, mult mai eficientă este soluŃiaprelucrării datelor pe server, într-o procedură scrisă în <strong>PL</strong>/<strong>SQL</strong>.<strong>PL</strong>/<strong>SQL</strong> este bazat pe limbajul ADA, o parte dintre construcŃiile salesintactice provenind din Pascal.Scrierea unui bloc anonimDe regulă programarea în <strong>PL</strong>/<strong>SQL</strong> înseamnă definirea unor proceduri saufuncŃii, în sensul pe care acestea le au în oricare dintre limbajele proceduralecunoscute. O procedură sau o funcŃie poate fi introdusă folosind fereastra <strong>SQL</strong>Plus sau folosind interfaŃa grafică, în <strong>SQL</strong> Command sau Script Editor.O succesiune de instrucŃiuni în <strong>PL</strong>/<strong>SQL</strong> care nu sunt destinate definiriiunei funcŃii sau proceduri formează un bloc anonim care va fi executat doar osingură dată.


58Exemplu:beginend;/dbms_output.put_line('Hello World');În fereastra <strong>SQL</strong>*Plus secvenŃa de cod scrisă va fi precedată de comandaset serveroutput onAceasta trebuie dată la începutul sesiunii de lucru şi realizează activareaafişării la consolă a rezultatului operaŃiilor de ieşire.Dacă se foloseşte interfaŃa grafică nu mai este necesară comandaset serveroutput on.


59Exemplul următor conŃine declaraŃia unei variabile, nr. Pentru a afişavaloarea acesteia se realizează conversia ei în şir de caractere folosind funcŃiato_char():Elementele limbajului <strong>PL</strong>/<strong>SQL</strong>Codul <strong>PL</strong>/<strong>SQL</strong> poate fi conŃinut în blocuri anonime sau în blocuri careconŃin subprograme memorate în baza de date (proceduri sau funcŃii).Un bloc anonim se introduce în fereastra în care se introduc comenzi<strong>SQL</strong>. El nu este memorat în mod normal în baza de date în vederea reutilizăriiulterioare. InterfaŃa serverului Oracle XE permite totuşi memorarea unui bloc,întocmai ca şi memorarea unei comenzi <strong>SQL</strong> orecare. Cele două exempleanterioare sunt blocuri anonime.Un subprogram memorat (denumit uneori stocat) este un subprogram<strong>PL</strong>/<strong>SQL</strong> pe care serverul Oracle îl compilează şi îl memorează în baza de date.Subprogramul memorat poate fi ulterior apelat dintr-o aplicaŃie sau dintr-un altbloc <strong>PL</strong>/<strong>SQL</strong>. Subprogramele pot fi proceduri sau funcŃii. DiferenŃa dintre celedouă este faptul că o funcŃie returnează o valoare.Un pachet (engl. package) este format dintr-un un grup de subprogrameşi de declaraŃii de variabile. Serverul Oracle memorează elementele conŃinuteîntr-un pachet, acestea putând fi apelate din alte pachete sau subprograme.Sintaxa unui bloc <strong>PL</strong>/<strong>SQL</strong>Un bloc anonim <strong>PL</strong>/<strong>SQL</strong> se compune din secŃiuni şi are sintaxaurmătoare:


60Bloc anonimDECLAREdeclaratii de variabileBEGINcod programEXCEPTIONcod tratare exceptiiEND;Dacă blocul conŃine o procedură memorată în baza de date, sintaxa saeste următoarea:Subprogram memorat de tip procedurăCREATE OR RE<strong>PL</strong>ACE PROCEDURE "nume"(lista_parametri)ISdeclaratii variabileBEGINcod programEXCEPTIONcod tratare exceptiiEND;SecŃiunea de declaraŃii (DECLARE în cazul blocului anonim) cuprindedeclaraŃii de variabile simple, variabile structurate, variabile tip cursor, funcŃiisau proceduri ajutătoare. Zona de declaraŃii este opŃională. Pentru funcŃii,proceduri şi triggere cuvântul DECLARE lipseşte, blocul de declaraŃii fiind implicitcuprins între linia de declarare a funcŃiei sau a procedurii şi BEGIN.Blocul introdus prin EXCEPTION este opŃional şi realizează tratareaerorilor apărute în timpul execuŃiei codului programului.Caracterul ';' se foloseşte pentru a marca sfârşitul unei instrucŃiuni sau aunui bloc, dacă apare după END.Codul poate cuprinde blocuri interioare. Exemplu:DECLAREdeclaraŃii variableBEGIN-- cod programBEGINcodul blocului inclusEXCEPTIONtratare exceptiiEND;-- cod program (continuare)END;


61Pentru transformarea exemplelor din următoarele subcapitole în exempleexecutabile, înaintea declaraŃiilor de variabile va fi introdus fie numele secŃiuniide date, DECLARE fie secvenŃa de declarare a unei proceduri stocate (CREATEOR RE<strong>PL</strong>ACE PROCEDURE "nume" IS).ComentariiÎn <strong>PL</strong>/<strong>SQL</strong> comentariile în linie se introduc prin două caractere '-' iarcomentariile pe mai multe linii sunt cuprinse între /* respectiv */, ca în limbajulC.Exemplu:Tipuri de date în <strong>PL</strong>/<strong>SQL</strong>Tipurile de date folosite în <strong>PL</strong>/<strong>SQL</strong> pot fi:1. cele folosite în <strong>SQL</strong> (VARCHAR2, NVARCHAR2, CHAR, NCHAR,NUMBER, BINARY_FLOAT, BINARY_DOUBLE, DATE, TIMESTAMP,CLOB şi BLOB),2. tipuri specifice limbajului <strong>PL</strong>/<strong>SQL</strong> : BOOLEAN, NUMBER (scrissimplu, fără dimensiune) şi <strong>PL</strong>S_INTEGER (pentru variabile avândvalori întregi),


623. tipuri specifice structurate: TABLE, VARRAY şi RECORD.Exemplu:-- Declaratii de variabilenume VARCHAR2(30);prenume VARCHAR2(25);marca NUMBER(6);activ BOOLEAN;salar_lunar NUMBER(6);nb_zile_lucrate NUMBER(2);salar_zilnic NUMBER(6,2);medie_zile_lucr CONSTANT NUMBER(2) := 21; -- o constantaBEGINNULL; -- NULL indica lipsa corpului. Este permisa pt. testare.END;/Obs. Pentru a defini constanta medie_zile_lucr s-a folosit cuvântulrezervat CONSTANT şi imediat s-a atribuit valoarea corespunzătoare.Variabilele declarate servesc de multe ori la memorarea unor valori dintabelele bazei de date, obŃinute folosind comenzi SELECT. În astfel de cazurieste esenŃial ca tipul declarat pentru o astfel de variabilă să coincidă cu tipulcoloanei tabelului din care va primi valori. Pentru a evita erorile greu de depistatcauzate de declararea eronată a acestor variabile, <strong>PL</strong>/<strong>SQL</strong> oferă soluŃia simplă apreluării tipului câmpului care va furniza valori folosind %TYPE, astfel:coded edituri.cod_edit%TYPE;Variabila coded va fi NUMBER(5), de acelaşi tip cu câmpul cod_edit dintabelul edituri.O situaŃe asemănătoare apare în cazul variabilelor structurate (de tipulRECORD). O astfel de variabilă va avea mai multe câmpuri. Dacă variabilatrebuie să preia valorile conŃinute într-o linie a unui tabel, la declararea ei se vafolosi %ROWTYPE, astfel:editura edituri%ROWTYPE;Variabila editura va fi de tip RECORD şi va avea aceleaşi câmpuri cutabelul edituri. Accesul la câmpuri se realizează folosind operatorul '.' (punct).Exemplu: editura.cod_edit, editura.nume etc.


63CursoareCursoarele permit programatorului să preia date dintr-o mulŃime deselecŃie, linie cu linie, în vederea prelucrării lor. În <strong>PL</strong>/<strong>SQL</strong> un cursor poate fiimplicit sau explicit.Cursorul implicit presupune utilizarea unei mulŃimi de selecŃie având osingură linie şi este folosit pentru a atribui valori unui set de variabile.Exemplu:SELECT cont, data, valoare into cnt, dt, val from operatii where cod_op = 3;În vederea selectării unei singure linii se impune valoarea cheii primare.Cursorul explicit are nume şi este declarat în secŃiunea de declaraŃii ablocului (procedurii, funcŃiei), astfel:CURSOR c1 IS SELECT ... ;Exemplu:CURSOR c1 IS SELECT nume, prenume FROM angajati WHERE functia = 'zidar';Comanda <strong>SQL</strong> SELECT va fi executată în momentul deschiderii cursoruluifolosind instrucŃiunea OPEN. Liniile mulŃimii de selecŃie conŃinute în cursor vor fiprelucrate individual, accesul la linia curentă realizându-se folosind instrucŃiuneaFETCH.După terminarea prelucrării datelor conŃinute într-un cursor, acestatrebuie închis folosind instrucŃiunea CLOSE.Câteva exemple privind folosirea cursoarelor vor fi înserate dupăprezentarea instrucŃiunilor repetitive.IdentificatoriNumele unei variabile constă dintr-un şir având maximum 30 caractere şiformat dintr-o literă urmată opŃional de alte litere, cifre, $, _. Caracterele '&', '-','/' şi ' ' (spaŃiu) nu sunt permise. <strong>PL</strong>/<strong>SQL</strong> nu este sensibil la tipul literelor -majuscule sau litere mici.Exemple:-- Declaratii de variabilenumeprenume VARCHAR2(30); -- identificator acceptat


64nume_prenume VARCHAR2(30); -- identificator acceptat, _ permisnume$prenume VARCHAR2(30); -- identificator acceptat, $ permisnume#prenume VARCHAR2(30); -- identificator acceptat, # permis-- nume-prenume identificator neacceptat, minus nepermis-- nume/prenume identificator neacceptat, / nepermis-- nume prenume identificator neacceptat, spatiu nepermis-- NUMEPRENUME identif. neacceptat, acelasi cu numeprenume siNumePrenume-- NumePrenume identif. neacceptat, acelasi cu numeprenume siNUMEPRENUMEBEGINNULL;END;/OperatoriLa scrierea codului în <strong>PL</strong>/<strong>SQL</strong> se folosesc următoarele tipuri de operatori:a. aritmetici: + - * /b. logici : '=' '>' '=' '


65END;/LiteraliExemple:-- Declaratii de variabilenumber1 <strong>PL</strong>S_INTEGER := 32000; -- literal numeric, val întreagănumber2 NUMBER(8,3);BEGINnumber2 := 3.125346e3; -- literal numericnumber2 := -8300.00; -- literal numericnumber2 := -14; -- literal numericEND;char1 VARCHAR2(1) := 'x'; -- literal caracterchar2 VARCHAR2(1);BEGINchar2 := '5'; -- literal caracterEND;/-- Declaratii de variabilestring1 VARCHAR2(1000);string2 VARCHAR2(32767);BEGINstring1 := '555-111-2323';-- daca un sir contine apostrof, acesta se dubleazastring2 := 'Here''s an example of two single quotation marks.';END;/-- Declaratii de variabilegata BOOLEAN := TRUE; -- BOOLEAN literalcomplet BOOLEAN;true_or_false BOOLEAN;BEGINgata := FALSE; -- literal BOOLEAN


66complet := NULL; -- literal BOOLEAN (valoare nedefinita)true_or_false := (3 = 4);true_or_false := (3 < 4);END;/-- Declaratii de variabiledate1 DATE := '11-AUG-2005'; -- literal DATEtime1 TIMESTAMP;BEGINtime1 := '11-AUG-2005 11:01:01 PM'; -- literal TIMESTAMPEND;/Atribuirea folosind SELECT ... INTODacă valoarea unei variabile se determină în funcŃie de valori dintr-o liniea unui tabel al bazei de date, <strong>PL</strong>/<strong>SQL</strong> permite atribuirea valorii acesteia folosindun cursor implicit, respectiv o construcŃieSELECT expresie INTO variabilă FROM tabel WHEREcondiŃie_selectare_linieExpresia folosită poate folosi variabile, literali şi valori din liniacorespunzătoare din tabel.Exemplu:-- Declaratii de variabileprocent_bonus CONSTANT NUMBER(2,3) := 0.05;bonus NUMBER(8,2);ang_id NUMBER(6) := 120; -- atribuie o val. pt testareBEGIN-- preia salar din tabelul angajati, calculeaza bonusul şi atribuie-- rezultatul -> variabila bonusSELECT salar * procent_bonus INTO bonus FROM angajatiWHERE angajat_id = ang_id;-- listeaza codul angajat_id, bonusul si procent_bonusDBMS_OUTPUT.PUT_LINE ( 'Angajat: ' || TO_CHAR(ang_id)|| ' Bonus: ' || TO_CHAR(bonus) || ' Procent bonus: ' ||TO_CHAR(procent_bonus*100));


67END;/În aceeaşi frază SELECT pot fi atribuite valori mai multor variabile.Exemplu:SELECT Nume, Prenume, salar*procent_bonus INTO m_nume, m_prenume,m_salarFROM angajati WHERE angajat_id = ang_id;FuncŃii uzuale<strong>PL</strong>/<strong>SQL</strong> cuprinde un număr mare de funcŃii. În tabelul de mai jos suntincluse cele mai des folosite.FuncŃiaFuncŃii pentru prelucrarea şirurilorupper(s), lower(s)ltrim(s), rtrim(s)Descriereconverteşte s în majuscule/minusculeînlătura spaŃiile de la stânga / dreaptasubstr(s, start, lungime)length(s)FuncŃii pentru prelucrarea datei calendaristicesysdateto_date(data, format)to_char(data, format)FuncŃii pentru date numericeround(x)mod(n, p)abs(x)power(x,n)dbms_random.random()Conversii de tipto_char(n)to_number(s)Alte funcŃiiuserreturnează un subşir definit prin poz. start şi lungimereturnează lungimea şirului de caractere sdata din sistemreturneaza o dată formatată conform formatuluiEx. : to_date('31-12-2007', 'dd-mm-yyyy')Converteşte o dată calendaristică în şir, conformformatului format. Exemplu:to_date(d, 'dd-mm-yyyy')rotunjeşte xreturnează restul împărŃirii întregi n/preturnează val. absolutăreturnează x ngenerează un număr aleator întregconverteşte n în şir de caractereconverteşte şirul s în numărreturnează numele utilizatorului serverului Oracle


68InstrucŃiuniSecvenŃele de cod scrise în <strong>PL</strong>/<strong>SQL</strong> pot conŃine comenzi <strong>SQL</strong> (CREATE,INSERT, DELETE, DROP sau ALTER).Exemplu:Insert into deponent values (124, 'Ionescu Valer', 'Str. Crinilor Nr. 7, Craiova','0743123989');Pe lângă comenzile <strong>SQL</strong> sau atribuirile de valori limbajul <strong>PL</strong>/<strong>SQL</strong> dispunede un set complet de instrucŃiuni necesare controlului execuŃiei programului, caoricare limbaj procedural.InstrucŃiunea de decidere - IFÎn limbajul <strong>PL</strong>/<strong>SQL</strong> instrucŃiunea IF poate prezenta trei forme.a. IF-THENExemplu:BEGINEND;/-- Declaratii de variabilevanzari NUMBER(8,2) := 10100;cota NUMBER(8,2) := 10000;bonus NUMBER(6,2);ang_id NUMBER(6) := 120;IF vanzari > (cota + 200) THENEND IF;bonus := (vanzari - cota)/4;UPDATE angajati SET salar = salar + bonus WHEREangajat_id = ang_id;Astfel scris IF serveşte la condiŃionarea unei acŃiuni. AcŃiunea estedeclanşată dacă expresia logică are valoarea adevărat. SecvenŃa de cod caredescrie acŃiunea este plasată între THEN şi END IF.


69b. IF-THEN-ELSEExemplu:BEGINEND;/-- Declaratii de variabilevanzari NUMBER(8,2) := 12100;cota NUMBER(8,2) := 10000;bonus NUMBER(6,2);ang_id NUMBER(6) := 120;IF vanzari > (cota + 200) THENELSEEND IF;bonus := (vanzari - cota)/4;bonus := 50;UPDATE angajati SET salar = salar + bonus WHEREangajat_id = ang_id;În secvenŃa anterioară prezenŃa clauzei ELSE permite definirea a douăblocuri de instrucŃiuni, unul cuprins între THEN şi ELSE şi al doilea cuprins întreELSE şi END IF. În funcŃie de valoarea de adevăr a expresiei logice va fi executatprimul bloc sau al doilea.c. IF-THEN-ELSIFUneori este necesară alegerea unei secvenŃe de cod din mai multe,fiecare fiind condiŃionată de câte o expresie logică. În acest caz se recomandăfolosirea structurii IF-THEN-ELSIF.Exemplu:-- Declaratii de variabilevanzari NUMBER(8,2) := 20000;bonus NUMBER(6,2);ang_id NUMBER(6) := 120;BEGINIF vanzari > 50000 THENbonus := 1500;ELSIF vanzari > 35000 THENbonus := 500;ELSE


70bonus := 100;END IF;UPDATE angajati SET salar = salar + bonus WHEREangajat_id = ang_id;END;/InstrucŃiunea CASEInstrucŃiunea CASE permite impunerea blocului care va fi executat înfuncŃie de valoarea unei expresii. De cele mai multe ori expresia se reduce la ovariabilă.Exemplu:BEGINEND;/-- Declaratii de variabilegrade CHAR(1);nivel := 'B';CASE nivelEND CASE;WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excelent');WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Foarte bun');WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Bun');WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('Corect');WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Slab');ELSE DBMS_OUTPUT.PUT_LINE('Nu ma pot pronunta');În exemplul prezentat valoarea variabilei nivel condiŃionează blocul careva fi executat. Valorile posibile sunt introduse prin clauze WHEN iar blocul deinstrucŃiuni care trebuie executat se scrie după THEN. Dacă valoarea variabileinivel nu se regăseşte printre valorile introduse prin WHEN, se va executa bloculintrodus prin clauza ELSE, plasată ultima. InstrucŃiunea se încheie cu END CASE.InstrucŃiuni de ciclareÎn limbajul <strong>PL</strong>/<strong>SQL</strong> există trei instrucŃiuni de coclare: LOOP, WHILE-LOOPşi FOR-LOOP.


71a. LOOPUn bloc LOOP - END LOOP permite definirea unui ciclu din care se ieseprin executarea unei instrucŃiuni EXIT. InstrucŃiunea EXIT este de regulă plasatăîntr-un IF a cărui condiŃie trebuie să ajungă să fie satisfăcută pentru a se evitarularea blocului LOOP în ciclu infinit.Exemplu:credit_rating NUMBER := 0;BEGINLOOPcredit_rating := credit_rating + 1;IF credit_rating > 3 THENEXIT; -- iesire imediata din loopEND IF;END LOOP;-- dupa EXIT, executia se continuă de aiciDBMS_OUTPUT.PUT_LINE ('Credit rating: ' || TO_CHAR(credit_rating));IF credit_rating > 3 THENRETURN; -- în afara blocului LOOP se foloseşte RETURN, nu EXITEND IF;DBMS_OUTPUT.PUT_LINE ('Credit rating: ' || TO_CHAR(credit_rating));END;/Dacă ieşirea din ciclu se poate realiza printr-un simplu IF, se poate înlocuiIF prin instrucŃiunea EXIT WHEN conditie_iesire.Exemplu:Exemplu:LOOPEND LOOP;IF count > 100 THEN EXIT; ENDIF;EXIT WHEN count > 100;credit_rating := credit_rating + 1;EXIT WHEN credit_rating > 3


72b. WHILE - LOOPÎn <strong>PL</strong>/<strong>SQL</strong> pentru realizarea unei structuri repetitive condiŃionate anteriorse utilizează instrucŃiunea WHILE - LOOP. Sintaxa unei astfel de structurirepetitive este următoarea:WHILE condiŃie LOOPEND LOOPbloc de instrucŃiunic. FOR - LOOPCa şi în alte limbaje, parcurgerea unui şir de valori se realizează folosindo instrucŃiune FOR - LOOP. Exemplu de utilizare:-- Declaratii de variabilep NUMBER := 0;BEGINFOR k IN 1..500 LOOP -- calcul pi ca suma a 500 termenip := p + ( ( (-1) ** (k + 1) ) / ((2 * k) - 1) );END LOOP;p := 4 * p;DBMS_OUTPUT.PUT_LINE( 'pi este aproximativ : ' || p );END;/În exemplul dat variabila i va lua valori în intervalul de valori întregiintrodus prin IN. Valorile sunt de regulă consecutive şi crescătoare. Dacă şirulvalorilor introduse prin IN trebuie parcurs în ordine inversă se va folosi clauzaREVERSE, ca în exemplul următor:BEGINEND;/FOR i IN REVERSE 1..5 LOOPEND LOOP;DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));Se interzice modificarea variabilei folosite la controlul ciclului în interiorulacestuia.Un exemplu tipic de utilizare a ciclului FOR în domeniul bazelor de dateeste cel în care se actualizează într-un ciclu înregistrările dintr-un tabel.Exemple:


73-- Declaratii de variabileCURSOR ang_cursor IS SELECT * FROM angajati;REC angajati%ROWTYPE; -- var. structurata de tip recordBEGINFOR REC IN ang_cursor LOOPUPDATE angajatiSET salar = ...WHERE ang_id = REC.ang_id;END LOOP;END;/CREATE OR RE<strong>PL</strong>ACE PROCEDURE AfisezASCURSOR c1 IS SELECT * FROM edituri order by nume;REC edituri%ROWTYPE; -- var. structurata de tip recordBEGINFOR REC IN c1 LOOPDBMS_OUTPUT.PUT_LINE (rec.nume);END LOOP;END;/BEGINOPEN c2;LOOPFETCH c2 INTO REC;-- preia linia curenta in RECEXIT WHEN c2%NOTFOUND;DBMS_OUTPUT.PUT_LINE( RPAD(REC.prenume, 25, ' ') ||REC.id_meserie );END LOOP;CLOSE c2;Notă FuncŃia RPAD() construieşte un şir de caractere având lungimeadată de al doilea argument. Şirul se obŃine prin completarea la dreapta a şiruluidat ca prim argument cu şirul dat ca al treilea argument.În exemplul următor cursorul c1 conŃine doar două valori din tabelulangajaŃi. InstrucŃiunea FETCH va prelua cele două valori în două variabile locale.


74jobid angajati.job_id%TYPE; -- variabila pentru id_functiepren angajati.prenume%TYPE; -- variabila pentru prenumeCURSOR c1 IS SELECT prenume, id_functie FROM angajatiWHERE id_functie LIKE '%ZIDAR';BEGINOPEN c1; -- deschid cursorul - execut selectLOOPFETCH c1 INTO pren, jobid; -- preiau 2 coloane in variabileEXIT WHEN c1%NOTFOUND;DBMS_OUTPUT.PUT_LINE( RPAD(pren, 25, ' ') || jobid );END LOOP;CLOSE c1;Definirea unei proceduriDe regulă secvenŃele de cod <strong>PL</strong>/<strong>SQL</strong> sunt conŃinute în proceduri saufuncŃii. Blocurile anonime pot fi folosite eventual pentru testarea corectitudiniiunei secvenŃe de cod, dar după încheierea testării ele vor fi transformate înproceduri sau funcŃii memorate în baza de date.Codul poate fi scris în fereastra destinată scrierii comenzilor <strong>SQL</strong> (<strong>SQL</strong>Command), în Script Editor sau folosind Object Browser / Create / Procedure.Indiferent de soluŃia adoptată, rezultatul va fi o procedură stocată în Oracle XE şiaccesibilă folosind meniul Object Browser.Exemplul 1. Crearea unei proceduri folosind <strong>SQL</strong> Command:


75Declararea unei proceduri folosind fereastra <strong>SQL</strong> Command sau <strong>SQL</strong>*Plusîncepe cu secvenŃa :CREATE OR RE<strong>PL</strong>ACE PROCEDURE nume ...Pentru verificarea creării procedurii se selectează Object Browser /Browse / Procedures şi în fereastra care se afişează se selectează procedura(SALUT).Exemplul 2. Crearea unei proceduri folosind Object Browser / Create /Procedure:Exemplu:


76În pasul următor se definesc parametrii de intrare şi de ieşire aiprocedurii, dacă este cazul.În continuare se introduce corpul procedurii:Rezultat:


77Astfel generată, procedurii îi lipseşte secŃiunea destinată declarăriivariabilelor locale. Pentru adăugarea acestora se selectează Edit şi se insereazădeclaraŃiile necesare.Apelul procedurii se poate realiza din fereastra destinată introducerii decomenzi <strong>SQL</strong> (<strong>SQL</strong> / <strong>SQL</strong> Commands) :Din <strong>SQL</strong>*Plus apelul se poate face şi folosind comanda <strong>SQL</strong> CALL :Parametrii procedurilor <strong>PL</strong>/<strong>SQL</strong>Procedurile pot avea un număr de parametri de intrare (IN), parametri deieşire (OUT) sau de intrare / ieşire (IN OUT).Exemple:PROCEDURE maj ( v1 IN VARCHAR2, v2 IN VARCHAR2) IS ...PROCEDURE majusc ( v1 IN VARCHAR2, v2 OUT VARCHAR2) IS ...PROCEDURE majuscule ( v1 IN VARCHAR2, v2 IN OUT VARCHAR2) AS ...Dacă un parametru este declarat de intrare (IN) modificarea sa însubprogram nu afectează valoarea eventualei variabile folosite ca parametruefectiv la apelarea funcŃiei.


78La apelul unei proceduri având parametri de tip OUT sau IN OUT, pepoziŃiile corespunzătoare acestora din lista de parametri efectivi trebuie utilizatevariabile de acelaşi tip cu cel al parametrilor procedurii.Un bloc anonim sau o procedură poate avea în zona de declaraŃii odeclaraŃie de procedură. Exemplu :DECLARE -- declaratii de variabile si subprogramenume VARCHAR2(20) := 'ionescu';prenume VARCHAR2(25) := 'marin';PROCEDURE nume_maj ( v1 IN OUT VARCHAR2, v2 IN OUT VARCHAR2) ASBEGINv1 := UPPER(v1); -- trec sirurile in majusculev2 := UPPER(v2);END;BEGINDBMS_OUTPUT.PUT_LINE(nume || ' ' || prenume ); -- afisez val. initialenume_maj (nume, prenume); -- apelez procedura cu parameteriDBMS_OUTPUT.PUT_LINE(nume || ' ' || prenume ); -- afisez noile valoriEND;/Deoarece procedura nume_maj este cuprinsă într-un bloc anonim,executarea blocului nu va determina memorarea acesteia în baza de date.Definirea unei funcŃiiFuncŃiile sunt subprograme care returnează o valoare. Ca şi în cazulprocedurilor, o funcŃie poate fi scrisă în fereastra destinată scrierii comenzilor<strong>SQL</strong> (<strong>SQL</strong> Command), în Script Editor sau folosind interfaŃa afişată prinselectarea opŃiunii Object Browser / Create / Function. Exemplu:


79FuncŃia salar poate fi apelată în mai multe moduri, cel mai simplu fiind înfraze select:a.b.Ca şi procedura, o funcŃie poate avea parametri de intrare. Listaacestora esteCREATE OR RE<strong>PL</strong>ACE FUNCTION nume_prenume ( nume IN VARCHAR2,prenume IN VARCHAR2, casatorit IN VARCHAR2)RETURN VARCHAR2 ASnup VARCHAR2(45); -- variabila localaBEGIN-- Se construieste un sir cuprinzand numele si prenumelenup := upper(nume) || ' ' || prenume;if length(casatorit) > 0 THEN -- daca e casatorit, adaug casatoritnup := nup || ' ' || casatorit;END IF;RETURN nup; -- returneaza valoarea lui nupEND;/Laborator nr. 5


80Laborator nr. 4RelaŃii între tabele. Comenzi <strong>SQL</strong> care selectează date din mai multe tabele1. PorniŃi aplicaŃia – Start -> Programs -> Oracle Database 10g Express Edition -> Go ToDatabaseHome Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.2. CreaŃi un utilizator nou, caine, cu parola caine3. CreaŃi o bază de date pentru evidenŃa câinilor de rasă din diferite Ńări.Pentru aceasta creaŃi următoarele tabeleTARITALIESCOPCAINE4. Se cere: cod_tara - cheie primară (număr) tara – tara de origine (caracter) cod_talie - cheie primară (număr) talie – marimea cainelui (caracter) cods - cheie primară (număr)scop - caracter cod_caine - cheie primară (număr) cod_tara – tara de origine (numar)cod_talie – talia cainelui (număr)rasa – rasa cainelui (caracter) cods – scopul folosirii cainelui (număr)• Să se adauge 10 Ńări, 5 talii, 6 scopuri şi 14 câinide diferite talii;TARI


81TALIESCOPCAINEFolosind editorul de interogări (Query Builder) şi salvând interogările sub formalab04_interogare1:• Să se afişeze toŃi câinii din toate Ńările:Fraza <strong>SQL</strong> corespunzătoare:select "CAINE"."RASA" as "RASA","TARI"."TARA" as "TARA"from "TARI" "TARI","CAINE" "CAINE"where "CAINE"."COD_TARA" =tari.cod_taraorder by CAINE.RASA ASC


82• Să se afişeze toŃi câinii dintr-o Ńară (de ex. Germania), indiferent de rasă.select "CAINE"."RASA" as "RASA","TARI"."TARA" as "TARA"from "TARI" "TARI","CAINE" "CAINE"where "TARI"."TARA" ='Germania'and "CAINE"."COD_TARA" =tari.cod_tararezultatul:• Să se afişeze toŃi câinii de talie medie dintr-o Ńară.select "CAINE"."RASA" as "RASA","TARI"."TARA" as "TARA","TALIE"."TALIE" as "TALIE"from "CAINE" "CAINE","TALIE" "TALIE","TARI" "TARI"where "TARI"."TARA" ='Germania'and "TALIE"."TALIE" ='medie'and "CAINE"."COD_TALIE" =talie.cod_talieand "CAINE"."COD_TARA" =TARI.COD_TARAorder by CAINE.RASA ASCrezultatul:• Să se afişeze toŃi câinii utilitari, indiferent de Ńară sau talie.selectfrom"CAINE"."RASA" as "RASA","SCOP"."SCOP" as "SCOP","TALIE"."TALIE" as "TALIE","TARI"."TARA" as "TARA""TARI" "TARI","TALIE" "TALIE",


83"SCOP" "SCOP","CAINE" "CAINE"where "CAINE"."CODS" =scop.codsand "SCOP"."CODS" =1andand"CAINE"."COD_TALIE" =talie.cod_talie"CAINE"."COD_TARA" =tari.cod_tararezultat:• Să se afişeze câinii de companie de talie mică din FranŃaselect "CAINE"."RASA" as "RASA","TARI"."TARA" as "TARA","TALIE"."TALIE" as "TALIE","SCOP"."SCOP" as "SCOP"from "SCOP" "SCOP","TALIE" "TALIE","TARI" "TARI","CAINE" "CAINE"where "TARI"."TARA" ='Franta'and "CAINE"."COD_TARA" =tari.cod_taraand "CAINE"."COD_TALIE" =1and "TALIE"."COD_TALIE" =caine.cod_talieand "SCOP"."SCOP" ='de companie'and "CAINE"."CODS" =scop.codsrezultat :5. CreaŃi câteva vederi (View):• afişaŃi câinii de talie mică, indiferent de scop şi ŃarăPentru asta alegeŃi succesiv Object Browser, Create, View


84?!?!……?!?!fraza <strong>SQL</strong>select "CAINE"."RASA" as "RASA","TALIE"."TALIE" as "TALIE"from "TALIE" "TALIE","CAINE" "CAINE"where "CAINE"."COD_TALIE" =1and "TALIE"."COD_TALIE" =caine.cod_talierezultat :


856. ScrieŃi o comandă <strong>SQL</strong> care să selecteze toŃi cânii dintr-o Ńară, indiferent de talie(numerotarea înregistrărilor se poate face apelând funcŃia rownum:select rownum, rasa, tara, talie from CAINe, tari, talie where caine.cod_tara = tari.cod_taraand caine.cod_talie = talie.cod_talie and tari.tara='Germania'rezultat :


86RelaŃii între tabele. Comenzi <strong>SQL</strong>.Laborator nr. 51. PorniŃi aplicaŃia – Start -> Programs -> Oracle Database 10g Express Edition -> Go ToDatabaseHome Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.2. CreaŃi un utilizator nou, banca, cu parola banca3. CreaŃi o bază de date pentru gestionarea unor informaŃii dintr-o bancă.Pentru asta creaŃi următoarele tabeleObs.DEPONENT cod_dep - cheie primară (number - 6,0) nume – numele şi prenumele deponentului (varchar2 - 60)adresa – adresa deponentului (varchar2 - 100)telefon – numărul de telefon al deponentului (number - 10)CONTURI cont – numărul contului (number - 6,0 – cheie primară)cod_dep – codul deponentului (number - 6,0 – cheie străină)OPERATII cod_op – codul operaŃiunii (cheie primară – number - 4)cont – numărul contului (number - 6,0, cheie străină ) data – data în care se efectuează operaŃiunea (dată)valoare – valoarea operaŃiunii, valoare pozitivă pentru depunere şi valoare negativăpentru retragere (număr) Un deponent poate avea mai multe conturi; Pentru un cont pot exista mai multe operaŃii în tabelul de operaŃii Depunerile vor fi pozitive (operatii.valoare >0) iar retragerile negative(operatii.valoare < 0)4. Se cere:• Să se adauge 5 clienŃi (deponenŃi), 7 conturi şi 11 operaŃii pentru diferite conturi;


87DEPONENTCONTURIOPERATII5. CreaŃi câteva vederi (View) – folosind Query Builder:


88• Să se afişeze , în ordine alfabetică, toŃi clienŃii bănciiDupă alegerea opŃiuniirezultatul esteDacă după compilare răspunsul este No Error, rezultatul va fi• Să se afişeze toate operaŃiunile bancare înordine crescătoare a datei


89• Să se afişeze toate operaŃiunile bancare efectuate într-o zi• Să se afişeze conturile unui deponent:Obs. AdăugaŃi legăturile persistente în fereastrta Query builder-ului• Să se afişeze toate operaŃiunile efectuate de un deponent într-un cont;


90• Să se afişeze toate conturile unui deponent precum şi suma totală pe care acesta oare în fiecare dintre conturi;


91• Să se afişeze toate retragerile efectuate în perioada 01-02-2007 – 31-03-2007;

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

Saved successfully!

Ooh no, something went wrong!