Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena
Mini tutorial de PL/SQL
Laboratoarele se bazeaz pe cursurile online oferite de ctre Oracle Academy. Pentru testarea exerciiilor in PL/SQL se vafolosi aplicaia proprietar Oracle: Oracle Application Express. Accesul la cursurile online valabile studenilor de la Informatic anul II se face la adresa web: http://academy.oracle.com/. Se alege linkul Introduction to computer science (stnga jos) -> Student Sign In (colul din dreapta sus), iar pe pagina de iLearning se va scrie un user i o parola furnizate n cadrul orelor de laborator. Pagina iLearning Accesul la Oracle Application Express se face la adresa web: https://iacademy3.oracle.com. Conturile sunt: Workspace: RO_P1268_S{useri de la 01 la 30} User: RO_P1268_S{nr folosit mai sus}_PLSQL Password: va fi comunicat Exemplu: School: RO_P1268_S03 User: RO_P1268_S03_PLSQL Password: ****** Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Oracle Application Express Pentru testarea exemplelor in PL/SQL se va folosi SQL Workshop -> SQL Commands. Introducere n PL/SQL Acest mini tutorial realizeaz o scurt introducere a limbajului de programare PL/SQL folosit n cadrul laboratoarelor de SGBD conform leciilor virtuale oferite de Academy Oracle. PL/SQL este un limbaj de programare procedural folosit de Oracle pentru bazele de date relaionale. Pe scurt PL/SQL este: - o extensie pentru limbajul SQL ce permite combinarea declaraiilor SQL cu un limbaj de programare; - este un limbaj proprietar Oracle i poate fi folosit doar cu o baz de date Oracle; - este un limbaj procedural; - este un limbaj de generaia a treia 3GL. Exemplu: Considerm tabela enrollments cu notele studenilor. Daca vrem s selectm notele atunci avem urmtoarea interogare: Select stu_id, final_numeric_grade, final_letter_grade From enrollments; Dac vrem n continuare s modificm datele n funcie de o anumit condiie dup principiul DAC este adevrat expresia ATUNCI execut instruciunea1, ALTFEL execut instruciunea2, nu putem doar cu declaraii SQL. Aici intervine PL/SQL care folosete variabile, costante, tipuri de date, cursoare, structuri de control i proceduri i funcii. n continuare vom oferi drept exemplu de utilizare a limbajului PL/SQL pentru modificarea notelor studenilor din valori numerice cu valori de tip caracter: Declare v_new_letter_grade varchar2(1); Cursor c_enrollments IS Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Select stu_id, final_numeric_grade from enrollments where class_id=1; Begin For c1 in c_enrollments Loop If c1.final_numeric_grade between 66 and 75 then v_new_letter_grade:= A: Elsif c1.final_numeric_grade between 56 and 65 then v_new_letter_grade:= B; Elsif c1.final_numeric_grade between 56 and 65 then v_new_letter_grade:= C; Elsif c1.final_numeric_grade between 56 and 65 then v_new_letter_grade:= D; Else V_new_letter_grade:=F; End if; Update enrollments Set final_letter_grade=v_new_letter_grade where class_id=1 and stu_id=c1.stu_id; End loop; Commit; End; Dup cum se poate observa limbajul folosete variabile definite n partea declarativ; folosete cursoare pentru situaii cnd avem mai mult de o nregistrare n urma unui select; structuri de control: FOR, IF; i declaraii SQL. Prin urmare avantajele PL/SQL sunt: - integrarea construciilor procedurale cu SQL; - integrarea structurilor de control cu SQL ceea ce ofer un control mult mai bun al instruciunilor SQL i al execuiilor acestora; - modularizarea programelor deoarece unitatea de baz ntr-un program PL/SQL este blocul considerat a fi un modul iar programul poate fi alctuit dintr-o secven de astfel de blocuri sau putem avea blocuri imbricate; - performan ridicat prin combinarea logic a declaraiilor SQL reducnduse numrul de apeluri la baza de date; - portabilitate, programele PL/SQL pot rula oriunde un server Oracle funcioneaz indiferent de SO i platforma folosit; - manipularea excepiilor, limbajul PL/SQL ofer posibilitatea captrii excepiilor eficient reducnd astfel posibilitatea apariiei erorilor. Crearea blocurilor PL/SQL Reprezint unitatea de baz n PL/SQL. Exist 3 tipuri de blocuri: blocul anonim, procedura i funcia, ultimele dou sunt subprograme. Un bloc PL/SQL conine trei pri: 1. Partea Declarativ (opional): ncepe cu DECLARE i se termin cnd partea executabil ncepe. Conine declaraii de variabile, cursoare i excepii definite de utilizator (exist i excepii predefinite). 2. Partea Executabil (obligatorie): ncepe cu BEGIN i se termin cu END. End se termin cu punct i virgul. Partea executabil poate conine oricte blocuri sunt necesare. 3. Partea de captare a Excepiilor (opional): partea aceast este inclus n partea executabil. ncepe cu EXCEPTION. a. Blocul anonim Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Exemplu: [ Declare .......] Begin .................... [ Exception ............... ] End; Blocul anonim nu poate fi invocat deoarece nu are un nume i nu mai exist dup ce este executat. Exemple de blocuri anonime: Begin DBMS_OUTPUT.PUT_LINE(un prim exemplu); End; -------------------------------------------------------------------------- Declare v_date DATE := sysdate; Begin DBMS_OUTPUT.PUT_LINE(v_date); End; ------------------------------------------------------------------------- Declare v_country_id varchar2(2); Begin select country_id into v_country_id from countries where country_id='a'; Exception WHEN NO_DATA_FOUND THEN Dbms_Output.Put_Line('eroare'); End; -------------------------------------------------------------------------- Observaii! Pentru exemplul cu exception avem o excepie predefinit: NO_DATA_FOUND. De asemenea se poate deduce ca i regul de declarare a variabilelor: folosirea literei v i apoi ct mai explicit denumiri pentru variabile. Funcia de afiare este DBMS_OUTPUT.PUT_LINE iar ca argumente pentru aceasta se folosesc variabile declarate i NU cmpuri din baza de date. De asemenea n cadrul codului PL/SQL rezultatul n urma unei interogri SQL se pstreaz tot ntr-o variabil declarat. Exe.: Begin Select 2*2 from dual, End; Este greit, iar eroarea va fi: PLS-00428: an INTO clause is expected in this SELECT statement. Corect este: Declare nr number; Begin Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena select 2*2 INTO nr from dual; End; b. Declararea subprogramelor: procedurilor i funciilor Subprogramele sunt stocate n baza de date i pot fi invocate ori de cte ori este necesar. 1. Procedur pentru a afia data curent CREATE PROCEDURE print_date IS v_date varchar2(30); BEGIN Select to_char(sysdate, Mon DD, YYYY) into v_date from dual; dbms_output.put_line(v_date); END; Cuvintele cheie sunt: CREATE PROCEDURE <nume> IS . Ea poate fi apoi apelat prin numele ei. 2. Funcie pentru a numra caracterele dintr-un string CREATE FUNCTION num_characters (p_string IN VARCHAR2) RETURN INTEGER IS v_num_characters integer; BEGIN Select length(p_string) into v_num_characters from dual; RETURN v_num_characters; END; Cuvintele cheie sunt: CREATE FUNCTION <nume> ( argument IN <tip data>) RETURN <tip> IS. Funciile fa de proceduri returneaz o valoare de un anumit tip de dat. Folosirea variabilele in PL/SQL Variabilele pot fi folosite pentru a stoca temporar datele, pentru manipularea valorilor stocate i pentru reutilizare. Ele sunt folosite n cadrul declaraiilor SQL astel: Select first_name, department_id INTO v_emp_fname, v_emp_deptno FROM ... unde v_emp_fname i v_emp_deptno sunt variabilele n care se vor stoca numele i departamentul; sau pot fi folosite ca parametri n subprograme PL/SQL i pentru a reine output-ul subprogramelor: CREATE FUNCTION num_characters (p_string IN VARCHAR2)RETURN INTEGER IS v_num_characters integer Toate variabilele trebuie declarate n seciunea declarativ a oricrui block PL/SQL! Iniializarea variabilelor Declare count INTEGER := 0; Begin Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena count :=count + 1; DBMS_OUTPUT.PUT_LINE(count); End; Dup cum se poate vedea variabila count a fost declarat n seciunea declarativ i totodata iniializat cu valoarea 0. Alte exemple de declarare i iniializare a variabilelor: data_azi DATE; numr NUMBER(2) NOT NULL :=2; constanta CONSTANT NUMBER :=10; nume VARCHAR2(30) DEFAULT Ema; Atribuirea valorilor n seciunea executabil Declare v_nume varchar2(20); Begin DBMS_OUTPUT.PUT_LINE(Numele meu este: || v_nume); v_nume := Ema; DBMS_OUTPUT.PUT_LINE(Numele meu este: || v_nume); End; Va afia: Numele meu este: Numele meu este: Ema SAU CREATE FUNCTION num_characters (p_string IN VARCHAR2)RETURN INTEGER IS v_num_characters integer; Begin Select length (p_string) into v_num_characters from dual; Return v_num_characters; End; Declare v_length_of_string integer; Begin --atribuirea variabilei v_length_of_string valoarea returnat de funcie v_length_of_string := num_characters(Oracle Academy); DBMS_OUTPUT.PUT_LINE(v_length_of_string); End; ! n cadrul blocurilor PL/SQL pentru comentariile pe o singur liniie se folosete -- , iar pentru cele pe mai multe linii /* */ Variabilele au urmtoarele proprieti: - pot avea maxim 30 de caractere - trebuie s nceap cu o liter - pot include simboluri precum $, _ i # - nu pot conine spaii - sunt case insensitive Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Tipurile de date in PL/SQL Exist cinci categorii de tipuri de date n PL/SQL. - Scalar - dein o singur valoare: character, number, date i boolean(Bacau, 234, 1-01-2010, true) - Compus - conin elemente interne care sunt fie scalare(recorduri) fie compuse(recorduri si tabele): table, record, nested table(tabel imbricat), varray - obiecte mari(LOB) - valoarea lor specific adresa obiectelor (precum imaginile): CLOB character large object(cri), BLOB binary large object(poze), BFILE binary file(filme), NCLOB national language character large objec(caractere chinezeti) - referin: pointeri - obiect: similar clasei din C++ i Java Folosirea tipul SCALAR Pentru variabile de tip caracter - CHAR: v_dept CHAR(7) - VARCHAR2: v_emp_job VARCHAR2(9) - LONG: v_name LONG Pentru variabile de tip numeric - NUMBER: v_dept_sal NUMBER(9,2) :=0 - PLS_INTEGER - BINARY_INTEGER: v_count Constant Binary_Integer:= 0 - BINARY_FLOAT ! INTEGER este acelai lucru cu NUMBER(38,0) Pentru variabile de tip dat - DATE: v_data DATE := sysdate+1 - TIMESTAMP: v_date TIMESTAMP - TIMESTAMP WITH TIMEZONE pentru zone cu diferene de fus orar Pentru variabile boolean - BOOLEAN cu cele trei valori posibile: true, false i NULL v_valid BOOLEAN:=true Atributul %TYPE Atrbutul poate fi folosit pentru a declara o variabil conform unei alte variabile declarate anterior sau a unei coloane dintr-o tabel. Este folosit n special atunci cnd declarm variabile pentru a stoca valori rezultate dintr-o tabel din baza de date. Variabila creat cu acest atribut va avea acelai tip de dat conform variabilei/coloanei dup care este declarat. Pentru a declara o variabil cu %TYPE atributul trebuie prefixat cu numele tabelei i numele coloanei conform creia declarm variabila. Exemplu: create table salariat (nume varchar2(30), id_salariat number(6) ); Declare v_id_salariat salariat.id_salariat%TYPE; Begin select id_salariat INTO v_id_salariat from salariat where nume like John End; SAU Declare v_cont NUMBER(7); Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena v_cont_debit v_cont%TYPE; . . . n aceste mod, variabila v_id_salariat va avea n mod automat acelai tip ca i coloana din tabela salariat. Atributul %Type este folositor pentru cazurile cnd schimbm tipul de dat pentru o coloan anume, iar n acest caz variabila creat pentru stocarea valorilor din coloana respectiv nu ar mai corespunde ca tip de dat(data type mismatch). Astfel nu mai trebuie s modificm apoi i tipul variabilei respective. Acesta este preluat automat indiferent de schimbare. Funcii SQL n PL/SQL Sunt disponibile n PL/SQL urmtoarele funcii: - single-row character - single-row number - date - data-type conversion Nu sunt disponibile n PL/SQL: - funcia decode - funciile de grupare (group functions) Exemple: -- obinerea lungimii unui ir v_lung INTEGER(5); v_sir VARCHAR2(70):= exemplu; v_lung := LENGTH(v_sir); -- rotunjirea unui numr la 0 decimale Declare v_median_age NUMBER(6,2); Begin DBMS_OUTPUT.PUT_LINE(ROUND(v_median_age, 0)); End; -- calcularea numrului de luni dintre dou date calendaristice Declare v_no_months PLS_INTEGER :=0; Begin v_no_months := MONTHS_BETWEEN(31-ian-09, 31-ian-10); DBMS_OUTPUT.PUT_LINE(v_no_months); End; n PL/SQL se pot efectua dou tipuri de conversii, explicite i implicite. !!NU uitai, conversiile implicite pot ncetini codul, putei pierde controlul asupra programului deoarece prin conversie implicite facei doar presupuneri despre cum Oracle manipuleaz datele, iar n caz c Oracle schimb regulile de conversie, codul nu va mai funciona. Este indicat s folositi conversii explicite: TO_NUMBER(), TO_CHAR(), TO_DATE(). BLOCURI IMBRICATE I SCOPUL VARIABILELOR Blocurile din PL/SQL pot conine oricte subblocuri. Exemplu: Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Declare V_outer-variable VARCHAR2(20) :=global variable; Begin Declare V_inner_variable VARCHAR2(20):=local variable; Begin DBMS_OUTPUT.PUT_LINE(v_inner_variable); DBMS_OUTPUT.PUT_LINE(v_outer_variable); End; DBMS_OUTPUT.PUT_LINE(v_outer_variable); End; n exemplul de mai sus avem un bloc exterior printe i un bloc interior copil. Variabila v_outer_variable este declarat n blocul printe i variabila v_inner_variable este declarat n blocul copil. Scopul unei variabile este n cadrul blocului sau blocurilor n care ea este accesibil, i anume unde poate fi denumit i folosit. n PL/SQL scopul unei variabile este n blocul unde a fost declarat plus blocurile imbricate n cadrul blocului. O variabil este local pentru blocul unde a fost declarat i globale pentru toate subblocurile acelui bloc: v_outer_variable este local pentru blocul outer i global pentru blocul inner. Nu pot exista dou variabile cu acelai nume n cadrul aceluiai bloc ns dou variabile pot avea acelai nume dac sunt din blocuri diferite. Vizibilitatea unei variabile este poriunea de program unde variabila poate fi accesat fr a folosi un calificator. Un calificator este o etichet dat unui bloc. Acest calificator este folosit pentru a accesa variabilele care au scop n cadrul altui bloc dar nu au vizibilitate. <<outer>> Declare v_nume_tata VARCHAR2(20):=Filip; v_zi_nastere DATE:=20-apr-1960; Begin Declare v_nume_copil VARCHAR2(20):=Mihai; v_zi_nastere DATE:=12-ian-1993; Begin DBMS_OUTPUT.PU_LINE(Tatal este || v_nume_tata); DBMS_OUTPUT.PUT_LINE(Zi de nastere || outer.v_zi_nastere); DBMS_OUTPUT.PU_LINE(Copilul este || v_nume_copil); DBMS_OUTPUT.PUT_LINE(Zi de nastere || v_zi_nastere); End; End; Se va afia: Tatal este Filip Zi de nastere 20-apr-1960 Copilul este Mihai Zi de nastere 12-ian-1993 Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Dup cum se poate observa din exemplul de mai sus, avem patru variabile, dou declarate n blocul etichetat outer i dou declarate n blocul copil imbricat blocului outer. Variabila v_nume_tata are scopul n ambele blocuri i vizibilitatea tot n ambele blocuri i este variabil local pentru blocul outer i global pentru blocul imbricat copil. Variabila v_nume_copil are scopul doar n blocul copil, unde a fost declarat i vizibilitatea la fel, i este variabil local pentru blocul interior. Variabila v_zi_nastere declarat n blocul outer are scopul n ambele blocuri dar are vizibilitate doar n blocul outer deoarece n blocul copil exist o variabil cu acelai nume, iar variabila din outer nu poate fi accesat decat prin calificatorul outer (pentru a ti exact c facem referire la aceat variabil). Este local pentru blocul outer i global pentru blocul copil. Variabila v_zi_nastere din blocul copil are scopul i vizibilitatea doar n blocul copil. Pentru a fi accesat nu este nevoie de calificator. Este local pentru blocul unde a fost declarat. Scopul excepiilor n blocurile imbricate O excepie este o seciune de program care prinde erorile pentru a nltura afritul brusc al programului. O excepie poate fi prins/manevrat sau propagat n mediul de execuie. Putem avea seciuni de manevrare a aexcepiilor n cadrul blocurilor interioare i dac excepia este tratat cu succes atunci blocul copil ii termin execuia iar blocul printe i-o continu n mod normal: Begin -- outer . . . Begin -- inner . . . Exception When exception_name Then -- excepia este tratat aici End; . . . End; Sau putem s lsm excepia s se propage n cadrul blocului printe (de fapt se caut n blocurile succesive seciunea de tratare a erorii pn se gsete una): Begin -- outer . . . Begin -- inner . . . End; . . . -- cum blocul interior nu a tratat eroarea, atunci aceasta este propagat n blocul exterior iar -- codul rmas din blocul exterior este srit Exception When exception_name then -- blocul printe va trata eroarea End; !n continuare, pentru a nelege mai bine teoria, este necesar s recapitulai JOIN-urile, funciile din SQL i sintaxa DML (data modeling language) pentru a insera, modifica, terge i reuni datele dintr-o baz de date i DDL (data definition language) pentru cearea, modificarea i tergerea obiectelor din baza de date. Regsirea i prelucrarea datelor n PL/SQL Declaraii SQL care pot fi folosite n PL/SQL sunt: - SELECT Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena - INSERT, UPDATE i DELETE - COMMIT, ROLLBACK i SAVEPOINT ! Nu se poate folosi DDL create table, alter table, drop table i grant, revoke direct n PL/SQL. Sintaxa SELECT n PL/SQL este: SELECT lista_cmpuri INTO {variabil1, variabil2, . . . | nume_record} FROM tabel [WHERE condiie] Clauza INTO este obligatorie i este folosit pentru a specifica numele variabilelor care vor deine valorile returnate n urma selectului. Trebuie specificat cte o variabil pentru fiecare cmp din tabel selectat i ordinea variabilelor trebuie s corespund cu ordinea cmpurilor din lista selectat. De asemenea clauza select trebuie s returneze doar un rnd, cele care vor returna mai mult de un rnd din tabel vor genera eroare. Exemplu: Declare v_salary employees.salary%TYPE; Begin SELECT salary INTO v_salary FROM employees; DBMS_OUTPUT.PUT_LINE(Salariul este || v_salary); End; Selectul de mai sus va returna mai mult de un rnd, i anume toate salariile pentru toi angajaii, iar variabila v_salary nu poate reine dect o singur valoare. Prin urmare se va genera eroare. ! Nu uitai: - s terminai fiecare instruciune SQL cu punct i virgul, - fiecare valoare trebuie stocat n variabile folosind clauza INTO, - specificai acelai numr de variabile cte cmpuri selectai, - declarai variabilele corespunztoare cmpurilor din tabel folosind atributul %TYPE, - nu folosii aceai denumire pentru variabile ca i cmpurile selectate (putei pune litera v n faa numelui). Insert n PL/SQL este folosit astfel: Begin INSERT INTO copy_emp (employee_id, first_name, last_name, email, hire_date, job_id, salary) VALUES (99, Ruth, Cores, RCORES,sysdate,AD-ASST, 4000); End; - o nou nregistrare este adugat n tabela copy_emp Update: Declare v_sal_increase employees.salary%TYPE :=800; Begin UPDATE copy_emp SET salary=salary + v_sal_increase WHERE job_id = ST_CLERK; End; Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena - modific salariul celor care sunt stock clerks tergerea datelor: Declare v_deptno employees.department_id%TYPE := 10; Begin DELETE FROM copy_emp WHERE department_id = v_deptno; End; - terge rndurile care aparin departamentului 10 Merge: Begin MERGE INTO copy_emp c USING employees e ON (e.employee_id = c.employee_id) When MATCHED THEN UPDATE SET c.first_name = e.first_name, c.last_name = e.last_name, c.email =e.email, . . . WHEN NOT MATCHED THEN INSERT VALUES (e.employees_id, e.first_name, . . . e.department_id); End; Folosirea clauzelor de control a tranzaciilor(operaii n baza de date) n PL/SQL Acestea sunt: COMMIT, ROLLBACK, SAVEPOINT. Exemple: Begin INSERT INTO pairtable VALUES (1,2); COMMIT; End; -- COMMIT este folosit pentru a face modificrile permanente Begin INSERT INTO pairtable VALUES (3,4); ROLLBACK; INSERT INTO pairtable VALUES (5,6); COMMIT; End; -- ROLLBACK este folosit pentru a anula orice modificare realizat n baza de date dup ultimul COMMIT realizat. n exemplul de mai jos doar ultimul insert are loc. Begin INSERT INTO pairtable VALUES (3,4); SAVEPOINT my_sp_1; INSERT INTO pairtable VALUES (9,10); SAVEPOINT my_sp_2; INSERT INTO pairtable VALUES (11,12); Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena ROLLBACK to my_sp_1; INSERT INTO pairtable VALUES (13,14); COMMIT; End; -- SAVEPOINT este folosit pentru a marca puncte intermediare n procesul tranzaciei. Doar ROLLBACK poate fi folosit cu SAVEPOINT. n exemplu prin ROLLBACK se anuleaz toate tranzaciile pn la savepoint my_sp_1. n final vor fi introduse doar primul insert i cel de dup rollback. CURSORUL IMPLICIT De fiecare dat cnd o instruciune SQL urmeaz s fie executat, serverul Oracle aloc o zon de memorie privat pentru a stoca declaraia SQL i datele implicate. Aceast zon de memorie se numete cursor implicit. Cu ajutorul atributelor cursorului implicit putem afla cte rnduri au fost procesate de ctre declaraia SQL. Exist dou tipuri de cursoare: - cursorul implicit, este automatic denumit SQL - cursorul explicit, definit de ctre programator pentru interogri ce returneaz mai mult de o nregistrare Atributele pentru cursorul implicit sunt: - SQL%FOUND atribut boolean evaluat cu true dac interogarea returneaz cel puin o nregistrare - SQL%NOTFOUND atribut boolean evaluat la true dac interogarea nu returneaz nicio valoare - SQL%ROWCOUNT este o valoare intreag ce reprezint numrul de nregistrri afectate de interogare Exemplu: Declare v_deptno copy_emp.department_id%TYPE:=50; Begin Delete from copy_emp where department_id = v_deptno; DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || nregistrri terse .); End; Structuri de control Structura Condiional IF IF condiie THEN Instruciune; [ELSIF condiie THEN Instruciune;] [ELSE Instruciune;] END IF; Declare V_varsta NUMBER:=13; Begin IF v_varsta < 18 THEN DBMS_OUTPUT.PUT_LINE (Sunt copil); ELSIF v_varsta < 40 THEN DBMS_OUTPUT.PUT_LINE (Sunt nc tnr); ELSE DBMS_OUTPUT.PUT_LINE(Sunt mereu tnr!); END IF; End; Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena !ATENIE: atunci cnd avem NULL n condiia din IF se comporta ca i FALSE, deci se va trece direct pe ramura urmtoare din IF. De exemplu: x :=5 i y:= NULL atunci IF x!=y va da NULL deoarece NULL este nedeterminat. La fel pentru x:= NULL i y:=NULL d tot NULL i instruciunile nu se execut. Structura CASE Exista dou tipuri de structuri CASE: Case-ul obinuit i 2 tipuri de expresii CASE care sunt funcii ce returneaz una din mai multe valori ntr-o variabil. CASE CASE [selector] WHEN expresie1 THEN instruciuni; WHEN expresie2 THEN instruciuni; . . . [ELSE instruciuni;] END CASE; Exemplu: Declare v_in NUMBER; Begin CASE v_in WHEN 1 THEN Select * from employees; WHEN 2 THE Select * from employees_copie; ELSE DBMS_OUTPUT.PUT_LINE(nu se selecteaz nimic); END CASE; End; Expresie CASE tip1: variabil := CASE selector WHEN valoare1 THEN rezultat1 WHEN valoare2 THEN rezultat2 . . . [ELSE rezultat n] End; Exemplu: Declare v_out VARCHAR2(15) := 50; v_in NUMBER; Begin v_out := CASE v_in WHEN 1 THEN mic WHEN 50 THE mijlociu ELSE alt valoare Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena END; DBMS_OUTPUT.PUT_LINE(v_out); End; Expresie CASE de cutare tip2: Case WHEN condiie_de_cutare1 THEN rezultat1 WHEN condiie_de_cutare2 THEN rezultat2 . . . [ELSE rezultat n] End; - nu are selector iar clauza WHEN conine o condiie de cutare care returneaz o valoare boolean i nu o expresie care poate returna o valoare de orice tip Exemplu: Declare v_out VARCHAR2(15) := 50; v_in NUMBER; Begin v_out := CASE -- nu mai avem selector WHEN v_in = 1 THEN mic WHEN v_in= 50 THE mijlociu ELSE alt valoare END; DBMS_OUTPUT.PUT_LINE(v_out); End; Structurile REPETITIVE: FOR, WHILE, LOOP LOOP structuta repetitiv de baz LOOP Instruciune1; . . . EXIT [WHEN condiie]; End LOOP; Exemplu: Declare v_counter NUMBER(3):= 1; Begin LOOP INSERT into salariat values (v_counter, Leonte,Bacau); v_counter:= v_counter+1; EXIT WHEN v_counter > 5; End loop; End; Putem avea oricte clauze EXIT dorim. Este indicat folosirea lui WHEN pentru a nu avea o bucl infinit. Bucla WHILE WHILE condiie LOOP /*dac condiia este adevrat se trece la execuia instruciunilor. Poate returna Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena true, false i NULL caz n care nu se execut while */ Instruciuni; . . . End LOOP; Declare v_counter NUMBER:=1; Begin While v_counter <= 3 LOOP INSERT into salariat values (v_counter, Leonte,Bacau); v_counter:=v_counter+1; End LOOP; End; Bucla FOR FOR contor IN [REVERSE] /*contor nu se declar este declarat implicit i este incrementat automat. Se folosete reverse pentru a decrementa contorul. */ Limita_minim . . limita_maxim LOOP -- limitele pot fi i expresii cu rezultat valoare numeric Instruciuni; . . . End LOOP; Begin FOR v_counter IN 1..3 LOOP INSERT into salariat values (v_counter, Leonte,Bacau); End LOOP; End; ! Structurile repetitive pot fi imbricate una n alta. Atunci structurile sunt etichetate <<etichet>> astfel nct putem specifica explicit din care bucl se iese: End LOOP <<etichet>>. Cursorul Explicit Este folosit atunci cnd n urma interogrii rezult mai mult de o nregistrare. Exemplu: se declar un cursor explicit pentru a obine numele i zile naionale pentru rile din Asia Declare CURSOR wf_holiday_cursor IS Select country_name, national_holiday_date From wf_countries where region_id IN (30, 34, 35); v_country_name wf_countries.country_name%TYPE; v_holiday wf_countries.nationa_holiday_date%TYPE; Begin OPEN wf_holiday_cursor; --nti se deschide cursorul LOOP -- bucl pentru parcurgerea tuturor nrgistrrilor obinute FETCH wf_holiday_cursor INTO v_country_name, v_holiday; EXIT WHEN wf_holiday_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_country_name || || v_holiday); End LOOP; CLOSE wf_holiday_cursor; --se nchide cursorul Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena End; Paii pentru folosirea unui cursor: 1. declare: declare nume_cursor IS instruciune_select; (selectul nu va mai conine clauza INTO) 2. open: open nume_cursor; - cursorul este poziionat pe prima nregistrare 3. fetch parcurgerea fiecrei nregistrri: fetch nume_cursor INTO variabil1, variabil2, . . . 4. close: close nume_cursor; Structura Record n cursor Este folosit pentru a uura munca cnd vrem s selectm toate cmpurile dintr-un tabel. Declare CURSOR wf_holiday_cursor IS Select * From wf_countries where region_id IN (30, 34, 35); v_holiday_record wf_holiday_cursor%ROWTYPE; Begin OPEN wf_holiday_cursor; LOOP FETCH wf_holiday_cursor INTO v_holiday_record; EXIT WHEN wf_holiday_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_holiday_record .v_country_name ); End LOOP; CLOSE wf_holiday_cursor; End; Alte atribute ale cursorului explicit sunt: %ISOPEN, %NOTFOUND, %FOUND, %ROWCOUNT Cursor FOR LOOP For nume_record IN nume_cursor LOOP -- nume_record este un cursor declarat implicit. Instruciuni; . . . End LOOP; Exemplu: Declare CURSOR wf_holiday_cursor IS Select * From wf_countries where region_id IN (30, 34, 35); Begin FOR v_holiday_record IN wf_cursor LOOP -- v_holiday_record a fost implict declarat ca wf_holiday_cursor%ROWTYPE EXIT WHEN wf_holiday_cursor%NOTFOUND; -- sau wf_holiday_cursor%ROWCOUNT>5 DBMS_OUTPUT.PUT_LINE(v_holiday_record .v_country_name ); End LOOP; -- nu se folosete OPEN i CLOSE cursor End; !n loc s folosim cursor se mai poate face i aa: FOR v_holiday_record IN (Select * from wf_countries where region_id IN (30, 34, 35); ) LOOP Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Cursor cu parametri CURSOR nume_cursor [(nume_parametru tip, . . .)] IS Instructiune select; -- fr clauza INTO Exemplu: Declare CURSOR wf_holiday_cursor(p_region NUMBER) IS Select * from wf_countries where region_id =p_region ; Begin FOR v_holiday_record IN wf_cursor(30) LOOP EXIT WHEN wf_holiday_cursor%ROWCOUNT>5 DBMS_OUTPUT.PUT_LINE(v_holiday_record .v_country_name ); End LOOP; End; Cursor FOR UPDATE CURSOR nume_cursor IS Select . . .from . . . FOR UPDATE [OF referin_coloan] [NOWAIT | WAIT n]; -referin_coloana este coloana ale crei rnduri le blocam - dac rndurile au fost deja blocate nowait returneaz imediat eroare. Dac se omite nowait atunci serverul Oracle va atepta pn cnd rndurile sunt disponibile - wait n ateapt n secunde i returneaz eroare dac alt sesiune blocheaz rndurile Cnd declarm un cursor FOR UPDATE fiecare rnd este blocat cnd deschidem cursorul. Acest lucru previne modificarea cursorului de ctre ali utilizatori ct timp cursorul este deschis, dar nu previne citirea rndurilor. Ne permite de asemenea s modificm noi cursorul prin clauza WHERE CURRENT OF pentru a ne referi la cea mai recent FETCH nregistrare: UPDATE employees SET salary = . . . WHERE CURRENT OF emp_cursor. Aceast clauz este folosit doar cu UPDATE i DELETE. Declare CURSOR wf_holiday_cursor IS Select * from wf_countries where region_id= 30 FOR UPDATE of region_id NOWAIT; Begin FOR v_holiday_record IN wf_cursor LOOP UPDATE wf_countries SET region_id=31 WHERE CURRENT OF wf_holiday_cursor; End LOOP; COMMIT; End; ! De asemenea exist cursoare imbricate i se deschid pe rnd i se nchid n ordinea descresctoare deschiderii lor. Tratarea EXCEPIILOR Exception handler este poriunea de program care definete aciunile ce au loc cnd o excepie apare EXCEPTION Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena WHEN exception1 [OR exception2] THEN -- NO_DATA_FOUND OR TOO_MANY_ROWS Instruciuni; . . . [WHEN OTHERS THEN Instruciuni; . . .] Cele de mai sus sunt excepii Oracle implicite. Exist i excepii non-predefinite. n acest sens orice programator poate declara explicit un anumit timp de excepie pentru a prinde o eroare nedefinit. Pentru aceasta trebuie: 1. declarate n DECLARE cu tipul EXCEPTION 2. asociem un numr de eroare standard Oracle ORA-n cu funcia PRAGMA EXCEPTION_INIT 3. tratarea erorii in seciunea EXCEPTION Exemplu: Declare e_insert_except EXCEPTION; (1) PRAGMA EXCEPTION_INIT(e_insert_except, -01400); (2) Begin Insert into departments (department_id, department_name) values (280, NULL); EXCEPTION WHEN e_insert_except (3) THEN DBMS_OUTPUT.PUT_LINE(insert failed); End; Putem lansa o eroare i n seciunea BEGIN astfel: Begin IF . . . THEN RAISE v_eroare; EXCEPTION WHEN v_eroare THEN . . . End; PROCEDURI CREATE [OR REPLACE] PROCEDURE nume [parametri] IS | AS [variabile, cursoare]; Begin Instruciuni SQL i PL/SQL; [Exception WHEN exception_nume;] End [nume]; Exemplu: CREATE OR REPLACE PROCEDURE add_salariat IS v_id salariat.salariat_id%TYPE:=20; v_nume salariat.salariat_nume%TYPE:=Mihaela; Begin INSERT INTO salariat values(v_id, v_nume); DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT ); --folosit pentru a testa dac insertul are loc End; Laboratoare SGBD Informatic anul II Instructor Vrlan Simona-Elena Invocarea Procedurilor ! Nu se poate invoca o procedur n cadrul unei instruciuni SQL precum SELECT. Begin add_salariat; End; Crearea procedurilor cu PARAMETRI CREATE OR REPLACE PROCEDURE add_salariat (v_id IN salariat.salariat_id%TYPE, -- este numit parametru formal v_nume IN salariat.salariat_nume%TYPE ) IS Begin INSERT INTO salariat values(v_id, v_nume); DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT ); End; Begin add_salariat(20, Mihaela); -- parametru actual End; Modul parametrilor este specificat n declararea parametrilor formali dup numele acestora i nainte de tipul lor. Un IN parametru ofer valori pentru prelucrare(pot fi doar citii n cadrul procedurii, nu pot fi modificai), un parametru OUT returneaz o valoare apelantului, iar un IN OUT parametru ofer o valoare de intrare care apoi poate fi returnat ca valoare modificat. FUNCII CREATE [OR REPLACE] FUNCTION nume [parametri [mode] tip] RETURN tip IS | AS [variabile]; Begin Instruciuni SQL i PL/SQL; RETURN expresie; End [nume]; Apelul se face: variabil := nume_funcie(parametri); SAU nume_funcie(parametri); ! Pentru a terge o procedur sau o funcie stocat se folosete DROP PROCEDURE|FUNCTION nume;