var <= var2 var3 LIKE '%S%' var4 BETWEEN '01-JUN-92' AND '01-SEP-92' var2 IS NOT NULL bool_var x IN ( 'Y', 'N', 'YES', 'NO' ) ( a = b OR c = 5 ) AND p < 400
IF conditie THEN actiuni [ ELSIF conditie THEN actiuni ] [ ELSE actiuni ] END IF;unde "actiuni" pot fi una sau mai multe instructiuni PL/SQL sau SQL, fiecare terminata cu punct-virgula. Aceste "actiuni" pot include alte instructiuni IF cu aceiasi structura, ceea ce inseamna ca instruciunea poate contine IF, ELSE, ELSIF imbricate.
IF v_ename = 'SCOTTY' THEN beam_me_up := 'YES'; COMMIT; END IF;Cele doua actiuni sind executate numai daca conditia este adevarata (TRUE). Daca conditia este falsa (FALSE sau NULL) atunci cele doua instructiuni sint excluse. In oricare din caz, executia continua cu urmatoarea instructiune din program de dupa END IF.
Notati ca daca constructia 'END IF' nu este prezenta la sfirsitul instructiunii, atunci PL/SQL ca cauta in instructiunile urmatoare cautind 'END IF'. Ca si in alte limbaje procedurale aceasta poate provoca afisarea unor mesaje de eroare confuze.
Urmatorul exemplu arata cum pot fi executate instructiuni alternative prin intermediul clauzei ELSE. Actiunile specificate prin ELSE sint executate daca conditiila este FALSE sau NULL, dupa care programul continua cu instructiunile ce urmeaza dupa END IF.
IF ename = 'SCOTTY' THEN beam_me_up = 'YES' ; COMMIT; ELSE beam_me_up = 'NO' ; ROLLBACK; END IF;
Oricare set de actiuni poate include instructiuni IF inlantuite pentru a executa teste ulterioare inainte ca o actiune specifica sa fie executata. Fiecare instructiune IF inlantuita trebuie sa fie terminata de END IF-ul corespunzator.
Exemplu:
IF deptno = 10 THEN accounting := 'YES'; IF job = 'MANAGER' THEN INSERT INTO status VALUES ( ' Dept10 Manager'); END IF; COMMIT; ELSE accounting := 'NO'; IF job = 'MANAGER' THEN INSERT INTO status VALUES (' Alt Mgr.'); END IF; COMMIT; END IF;
Adesea, actiunile de executat in clauza ELSIF pot contine doar un alt IF. In aceasta situatie, este mult mai convenabil sa folositi clauza ELSIF, care elimina necesitatea de a inlantui END IF la sfirsitul fiecarui set ulterior de conditii/actiuni:
IF f_title = 'doamna' THEN status := 'MARITATA'; ELSIF f_title = 'domnisoara' THEN status := 'NEM.' ELSE status:= 'NECUNOSCUTA'; END IF;Datorita posibilitatii de a imbrica actiuni, clauza ELSIF poate fi utilizata recursiv, daca doriti:
IF choise = 1 THEN actiune := 'Run Payroll' ; ELSIF choice = 2 THEN actiune := 'Run Accounts'; ELSIF choice = 3 THEN actiune := 'Backups'; ELSIF choice = 4 THEN actiune := 'Restore'; ELSE actiune := 'Invalid'; END IF;
Structura:
LOOP -- actiuni de executat in -- cadrul ciclului END LOOP; * EXIT termina ciclul
Sintaxa:
EXIT [eticheta-ciclu] [WHEN conditie];
LOOP -- actiuni de executat -- in cadrul ciclului END LOOP;De fiecare data cind programul ajunge la constructia END LOOP, controlul este redat expresiei LOOP corespunzatoare. Acest ciclu necontrolat va fi, bineinteles, infinit daca nu se folosesc instructiuni de control in interiorul ciclului, care sa provoace saltul in afara ciclului.
Sintaxa:
EXIT [loop-label] [WHEN conditie];EXIT poate fi executat fie ca o actiune dintr-un IF, sau ca o instructiune individuala in cadrul unui ciclu. In acest caz, o clauza WHEN poate fi atasata la instructiunea IF, permitind terminarea conditionata a ciclului.
Exemplul 1:
LOOP counter := counter + 1; INSERT INTO numbered_rows VALUES (counter); ... IF counter = 10 THEN COMMIT; EXIT; END IF; END LOOP;
Exemplul 2:
LOOP ... EXIT WHEN total_sals = 60000; ... END LOOP;
O alta posibilitate de a iesi dintr-un ciclu ar fi sa sariti la o
instructiune etichetata in afara ciclului, folosind instructiunea GOTO.
Aceasta este in general considerata ca o metoda mai putin structurata.
GOTO si etichetele vor fi discutate mai tirziu, in acest capitol.
Utilizarea ciclurilor FOR pentru controlul iteratiilor
Ciclurile FOR au aceeasi structura generala ca si celee pe care deja le-ati vazut, dar adauga instructiuni de control la inceputul ciclului, care vor determina numarul de iteratii ce vor fi efectuate.
Sintaxa:
FOR variabila_control IN [REVERSE] valoare_inferioare .. valoare_superioara
Unde 'variabila_control' este numele unei variabile intregi ale carei valori vor fi incrementate/decrementate automat la fiecare iteratie a ciclului. Aceasta variabila este creata de catre ciclu, si nu poate fi scrisa de nici o instructiune din cadrul ciclului. Durata de viata se termina la terminarea ciclului.
'valoare_inferioara' si 'valoare_superioar' sint expresii intregi, care determina valorile pe care le va lua variabila de control.
Implicit, variabila de control este initializata cu o valoare mica, si este incrementata cu +1 la fiecare iteratie pina cind valoarea superioara este atinsa.
Exemplu:
FOR i IN 1 .. 2000 LOOP INSEERT INTO numbered_rows VALUES (i); preserve_i := i; ... END LOOP;
Observati ca daca valoarea lui 'i' este necesara dupa terminarea ciclului, atunci ea trebuie copiata intr-o variabila declarata inainte de terminarea ciclului.
Ciclul FOR poate si sa decrementeze variabila de control, incepind de la valoarea superioara in prima iteratie:
FOR n IN REVERSE 50 .. myvar+50 LOOP -- n are valoarea myvar+50 la prima iteratie. -- si valoarea 50 la ultima END LOOP;
Aceasta este o structura de control alternativa, care permite iteratiilor sa fie executate conditionat.
Sintaxa:
WHILE conditie
Conditia este evaluata la inceputul fiecarei iteratii, si ciclul este terminat cind conditia este FALSE. Daca conditia este FALSE atunci cind ciclul incepe, atunci nici o interatie nu se executa.
Exemplul 1:
WHILE bill <250 AND food LIKE '%taco%' LOOP -- actiuni END LOOP;
Exemplul 2:
WHILE bool_var LOOP -- actiuni END LOOP;
Normal, daca variabila implicata in conditii nu se schimba in timpul
executiei ciclului, atunci ciclul nu se va termina niciodata. Totusi
instructiunea EXIT poate fi inclusa atit in ciclurile FOR si WHILE.
Controlul ciclurilor imbricate
Ciclurile pot fi imbricate pe nivele multiple. Puteti imbrica cicluri FOR in cicluri WHILE si invers. In mod normal, terminarea unui ciclu intern nu termina ciclul care il include, exceptind cazul cind este generata o exceptie.
Etichetele in PL/SQL sint definite astfel:
<< label-name >>
Numele etichetei urmeaza aceleasi reguli ca si orice identificatori. O eticheta este plasata inaintea unei instructiuni, fie pe aceasi linie, fie pe o linie separata.
Ciclurile pot fi etichetate prin plasatea unei etichete inainte de cuvintul LOOP, si dupa END LOOP, conform:
<< outer_limits >> LOOP -- actiuni END LOOP outer_limits;
Daca un ciclu subordonat executa un EXIT, atunci el poate specifica care ciclu sa fie incheiat prin specificarea etichetei.
Exemplu:
<< main >> LOOP ... LOOP ... EXIT main WHEN total_done = 'YES'; -- paraseste ambele cicluri EXIT WHEN inner_done = 'YES'; -- paraseste doar ciclul interior END LOOP main;
Dupa cum ati vazut, etichetele pot fi utilizate pentru a identifica cicluri atunci cind apar in structuri inlantuite. Aceasta este si cazul blocurilor inlantuite. O eticheta poate fi plasata inaintea inceputului si dupa sfirsitul unui bloc PL/SQL, astfel incit identitatea sa declarate sa poate fi deosebita de celelalte blocuri din structura inlantuita. Sa luam exemplul urmator:
DECLARE var1 NUMBER; BEGIN . DECLARE var1 NUMBER := 400; BEGIN . var1 := var1 + 1 ; -- var1 din subbloc se mareste cu 1 . END; . END;
Variabila var1 care a fost declarata in blocul exterior nu se "vede" in cadrul blocului interior, deoarece acesta a declarat o variabila cu acelasi nume. Toate referirile la 'var1' din sub-bloc vor fi deci folosite pentru variabila local declarata.
Totusi, daca blocurile sint etichetate, identificatorii pot fi referiti prefixati de numele blocului dorit. (Observatie: blocul exterior nu trebuie neaparat etichetat). Un exemplu:
BEGIN <> DECLARE var1 NUMBER; . BEGIN . < > DECLARE var1 NUMBER := 400; BEGIN . block1.var1 := block1.var + 1; -- variabila din block 1 -- este incrementata END block2; END block1; END;
Asa cum s-a aratat, END poate include numele blocului care trebuie terminat.
Aceasta instructiune ofera salturi neconditionate la o eticheta in cadrul unui program PL/SQL. Utilizarea instructiunii trebuie minimizata, deoarece folosirea excesiva poate duce la programe foarte dezorganizate.
Valabilitatea unei etichete este in intregul bloc in care a fost definita. GOTO poate, deci, transmite controlul catre puncte etichetate din blocul curent sau catre un punct etichetat dintr-un alt bloc care contine blocul curent.
Sintaxa:
GOTO eticheta;
Unde 'eticheta' poate fi orice eticheta care marcheaza o pozitie in
cadrul blocului curent sau al altuia ce il cuprinde. GOTO nu poate
transmite controlul in interiorul unui sub-bloc.
Exercitii pentru capitolul 22
UPDATE messages SET numcol2 = 100 WHERE numcol1 = V ;Daca rularea UPDATE produce altceva decit un singur rind, atunci se va iesi din ciclu.( Puteti testa atributul SQL%ROWCOUNT, asa cum este discutat in capitolul 23).
BEGIN FOR v_count IN 1..10 LOOP IF v_count NOT IN (6,8) THEN INSERT INTO messages (numcol1) VALUES (v_count); END IF; END LOOP; COMMIT; END;
DECLARE v_ename emp.ename%TYPE; v_hiredate emp.hiredate%TYPE; v_sal emp.sal%TYPE; v_message CHAR(30); BEGIN SELECT ename, hiredate, sal INTO v_ename, v_hiredate, v_sal FROM emp WHERE empno = &EMPLOYEE_NO ; IF v_sal > 1200 THEN v_message := 'Salariu mai mare de 1200'; ELSIF v_ename LIKE '%T%' THEN v_message := 'Numele contine "T"'; ELSIF TO_CHAR(v_hiredate, 'MON') = 'DEC' THEN v_message := 'Decembrie'; ELSE v_message := '** Nimic **'; END IF; INSERT INTO messages (charcol1) values (v_message); END;
BEGIN FOR v IN 1 .. 10 LOOP UPDATE messages SET numcol2 = 100 WHERE numcol1 = v; EXIT WHEN SQL%ROWCOUNT <> 1; END LOOP; END;