Sunteți pe pagina 1din 6

Programe simple în PL/SQL

Instrucţiunea SELECT în PL/SQL funcţionează doar dacă rezultatul interogării este un singur
tuplu. Situaţia este identică cu SELECT -ul care furnizează o singură înregistrare despre care am
vorbit la interogări. Dacă interogarea returnează mai mult de un tuplu, trebuie să folosim o tabelă
cursor. De exemplu:

DROP TABLE T1;


CREATE TABLE T1(
nume VARCHAR(20),
salar INTEGER
);
DELETE FROM T1;
INSERT INTO T1 VALUES(’POPESCU Ion’, 600);
INSERT INTO T1 VALUES(’BALAJ Maria’, 500);
INSERT INTO T1 VALUES(’AVRAM Alina’, 700);
SELECT * FROM T1;
/* Deasupra e SQL simplu, mai jos este un program PL/SQL */
DECLARE
    v_nume VARCHAR(20);
    v_salar NUMBER;
BEGIN
/* Pentru cei care au salarul=500, acesta se mareste cu 100*/
SELECT nume, salar INTO v_nume,v_salar FROM T1 WHERE salar=500;
DELETE FROM t1 WHERE salar=500;
INSERT INTO T1 VALUES(v_nume,v_salar+100);
END;
.
run;
/* din nou SQL simplu */
SELECT * FROM T1;

Din fericire, un singur tuplu din tabela T1 verifică condiţia ca salarul să fie egal cu 500, şi anume
(BALAJ Maria, 500). Comanda DELETE şterge înregistrarea respectivă, urmând ca INSERT să
o introducă din nou în tabelă, de data asta cu salarul mărit.

Alt exemplu:

CREATE TABLE T2 (nr1 INTEGER, nr2 INTEGER);

DELETE FROM T2;

INSERT INTO T2 VALUES(1, 3);


INSERT INTO T2 VALUES(2, 4);

/* Deasupra este SQL; mai jos program PL/SQL */

DECLARE
v_nr1 NUMBER;
v_nr2 NUMBER;
BEGIN
/* daca primul numar este mai mare ca 1, se inverseaza insereaza o
inregistrare noua in care numerele sunt inversate*/
SELECT nr1,nr2 INTO v_nr1,v_nr2 FROM T2 WHERE nr1>1;
INSERT INTO T2 VALUES (v_nr2,v_nr1);
END;
.
run;
Programele PL/SQL sunt organizate în funcţii, proceduri şi pachete (similare oarecum pachetelor
Java). PL/SQL este bazat pe limbajul de programare Ada şi împarte multe elemente de sintaxă cu
Pascal-ul.

Clauza run execută o declaraţie care crează procedura – nu execută procedura... Pentru a executa
o procedură, este indicat să folosim un bloc PL/SQL în care să invocăm procedura ca o declaraţie
executabilă. De aceea este preferabil NU să folosim blocuri anonime, ci proceduri sau funcţii
denumite.

Execuţia PL/SQL.
Dacă avem un bloc anonim, acesta va fi executat imediat. Dacă utilizăm proceduri şi funcţii,
acest lucru nu se mai întâmplă. Pentru a lansa în execuţie o procedură sau o funcţie, o vom apela
în cadrul unei declaraţii SQL.
declare
2 /* declaratii*/
3 prima_variabila INTEGER;
4 a_doua_variabila VARCHAR2(50);
5 a_treia_variabila DATE;
6 a_patra_variabila BOOLEAN;
7 BEGIN
8 --aici se scriu comenzile efective
9 DBMS_OUTPUT.PUT_LINE('HELLO!');
10 END;
11 /

Acum vom rescrie blocul anonim ca o procedură.

CREATE OR REPLACE PROCEDURE hello


IS
user_name VARCHAR2(8) := user;
BEGIN -- `BEGIN' ex
dbms_output.put_line('Hello, '
|| user_name || '!');
END;
/

Observaţii:

 Variabila user_name o declarăm ca fiind de tipul VARCHAR2


 user_name este iniţializată utilizând funcţia user – funcţie specifică, care recunoaşte
userul cu care ne-am conectat (scott) - dacă funcţia nu are nici un parametru, nu trebuie
puse (), ca şi în SQL
 ``:='' este operatorul de atribuire.

Pentru a executa procedura, se utilizează comanda EXEC.

SQL> EXEC welcome

Legat de declararea tipurilor de date create vom utiliza sintaxa:

DECLARE
...
TYPE t_personal IS RECORD(
Marca personal.marca%TYPE,
Numepren personal.numepren%TYPE,
...
)
rec_personal t_personal;
sau

DECLARE
...
rec_personal personal%ROWTYPE;

Încorporarea SQL în PL/SQL


PL/SQL nu permite interogarea bazelor de date şi folosirea rezultatelor în cadrul programului.
Totuşi, orice SQL poate fi încorporat în cod PL/SQL. Există o modalitate de a utiliza fraza
SELECT pentru a asigna rezultatul unei interogări unei variabile.

Exemplu:
Având tabelele: Facturi (nrfact, datafact) şi Produse (ID, nrfact, denprod, cant, pret) dorim să
numărăm câte produse sunt pe o anume factură specificată prin numărul facturii.

1 CREATE OR REPLACE PROCEDURE count_nrprod


2 (nrfact_param NUMBER)
3 IS
4 prod_count NUMBER;
5 BEGIN
6 SELECT COUNT(*) INTO prod_count
7 FROM facturi f, produse p
8 WHERE f.nrfact = p.nrfact AND f.nrfact = nrfact_param;
9
10 IF prod_count > 1 THEN
11 dbms_output.put_line('Sunt '
12 || prod_count || ' produse.');
12 ELSIF prod_count = 1 THEN
14 dbms_output.put_line('Exista 1 produs.');
15 ELSE
16 dbms_output.put_line('Nu exista nici un produs.');
17 END IF;
18 END;
19 /

Observaţii:

 Procedura are un parametru – numărul facturii, de tip NUMBER


 Procedura se numeşte count_nrprod
 O valoarea a unei interogări SQL este asignată unei variabile PL/SQL (prod_count)
utilizând SELECT...INTO... (linia 6)
 O valoare a unei variabile PL/SQL este utilizată într-o clauză SQL (linia 8)

Pentru a executa procedura cu mai multe numere de factură:


EXEC count_nrprod(123)
EXEC count_nrprod(234)

Lucrul cu cursoare
Se doreşte afişarea numărului de produse pentru fiecare număr de factură în parte. Diferenţa faţă
de exemplul anterior este numărul de înregistrări (multiple, nu o singură valoare).Aşadar, o
instrucţiune SELECT...INTO... poate recupera datele de la (cel mult) un tuplu în variabile
individuale.

Cursoarele permit recuperarea liniilor multiple într-o zonă tampon (buffer) atunci când acestea
sunt deschise utilizându-se comanda OPEN <cursor>. Acestea pot fi traversate secvenţial
utilizându-se comanda FETCH pentru a recupera linii individuale – până când nu mai sunt date,
adică variabila cur_prod%NOTFOUND devine adevărată.

CREATE OR REPLACE PROCEDURE count_dupa_nrfact


IS
nrf NUMBER;
cnt NUMBER;
CURSOR cur_prod IS
SELECT f.nrfact, COUNT(f.nrfact) AS nr_prod
FROM facturi f, produse p
WHERE f.nrfact = p.nrfact GROUP BY f.nrfact;
BEGIN
OPEN cur_prod;
LOOP
FETCH cur_prod INTO nrf, cnt;
EXIT WHEN cur_prod%NOTFOUND;

IF cnt = 0 THEN dbms_output.put_line('Nu există produse pentru factura cu


nr '
|| nrf);
ELSE
dbms_output.put_line(cnt || ' produs(e)pentru factura cu numarul ' ||
nrf);
END IF;

END LOOP;
CLOSE CUR_prod;
END;
/

Executaţi count_dupa_nrfact, adăugând mai multe date tabelei, dacă este necesar.

Cursoare
Un cursor este o variabilă care permite trecerea prin mai multe tupluri ale unei tabele. Putem
scrie un program care să citească şi să proceseze valorile fiecărui tuplu (utilizând un bloc
anonim). Putem, de asemenea, dacă datele sunt salvate într-o tabelă, să actualizăm sau să
ştergem tuplul curent.

Exemplul de mai jos ilustrează un ciclu cu cursor. Acesta utilizează tabela T2, care conţine
perechi de numere întregi. Programul va şterge orice tuplu a cărui prim element este mai mic
decât al doilea, şi va insera inversul tuplului în tabela T2.

1) DECLARE
/* Variabilele de ieşire care vor reţine rezultatele interogării:*/
2) a T2.nr1%TYPE;
3) b T2.nr2%TYPE;
/* Declararea cursorului: */
4) CURSOR T2Cursor IS
5) SELECT nr1, nr2
6) FROM T2
7 WHERE nr1 < nr2;
8
9) BEGIN
10) OPEN T2Cursor;
11) LOOP
/* Regăsirea fiecărei linii ca rezultat al interogării în
variabile PL/SQL */
12) FETCH T2Cursor INTO a, b;
/* Dacă nu mai există înregistrări, ieşirea: */
13) EXIT WHEN T2Cursor%NOTFOUND;
/* Stergerea tuplului curent: */
14) DELETE FROM T2 WHERE CURRENT OF T2Cursor;
/* Insarea tuplului inversat: */
15) INSERT INTO T2 VALUES(b, a);
16) END LOOP;
/* Închiderea cursorului utilizat. */
17) CLOSE T2Cursor;
18) END;
19) .
20) run;

Observaţii:
 Linia (1) secţiunea de declarare de variabile.
 Linia (2) şi (3) declară variabilele a şi b ca având acelaşi tip cu cel al câmpurilor nr1 şi
nr2 din tabela T2. Deşi ştim că aceste câmpuri sunt de tip INTEGER, este preferabil să
utilizăm opţiunea Type.
 Liniile de la (4) la (8) definesc cursorul T2Cursor. Acesta acţionează asupra unui
domeniu definit de o interogare SELECT-FROM-WHERE. Înterogarea selectează doar acele
tupluri din T2 a cărui primă componentă este mai mică decât cea de-a doua componentă.
 Linia (9) – începutul secţiunii executabile a programului.
 Linia (10) deschide cursorul – un pas esenţial.
 Liniile de la (11) la (16) conţin ciclul PL/SQL. Un astfel de ciclu este încadrat între LOOP
şi END LOOP. În corpul ciclului găsim:
o În linia (12) se salvează datele din cursor în variabile. În general, declaraţia FETCH
trebuie să conţină variabile pentru fiecare componentă a tuplului furnizat.
Interogarea dintre liniile (5) şi (7) produce perechi, deci s-au furnizat două
variabile de tipul care trebuia.
o În linia (13), se testează condiţia de ieşire din ciclu. Însemnănatea este evidentă:
%NOTFOUND după numele cursorului este adevărată atunci când nu se mai găsesc
tupluri în cursor.
o În linia (14), DELETE şterge înregistrarea curentă folosind clauza WHERE condiţia
CURRENT OF T1Cursor.
o În linia (15), instrucţiunea INSERT inserează inversul tuplului în tabela T2.
 Linia (17) închide cursorul.
 Linia (18) închide programul PL/SQL.
 Liniile (19) şi (20) forţează programul să se execute.

Instrucţiuni de control în PL/SQL


PL/SQL permite crearea unor decizii sau cicluri.

O instrucţiune IF are formatul general:

IF <conditie> THEN <lista_declaratii> ELSE <lista_declaratii> END IF;

Partea ELSE este opţională. Dacă se doreşte imbricarea:


IF <conditie_1> THEN ...
ELSIF <conditie_2> THEN ...
... ...
ELSIF <conditie_n> THEN ...
ELSE ...
END IF;

Ciclurile pot fi create astfel:


LOOP
<corpul_ciclului> /* O listă de declaraţii */
END LOOP;

Cel puţin o declaraţie din <corpul_ciclului> ar trebui să fie o declaraţie EXIT:


EXIT WHEN <conditie>;

Ciclurile se termină dacă condiţia <conditie> este adevărată.


 EXIT permite ieşirea necondiţionată din ciclu. Dacă se doreşte, se poate utiliza în cadrul
unei decizii.
 Ciclul WHILE va avea următorul format general:

WHILE <conditie> LOOP


<corpul_ciclului>
END LOOP;
 Ciclul FOR va avea următorul format general:

FOR <variabila> IN <inceput>..<final> LOOP


<corpul_ciclului>
END LOOP;

Aici, <variabila> poate fi orice variabilă, aceasta este locală For-ului şi nu trebuie declarată,
<inceput> şi <final> fiind constante.

Temă: Să se creeze tabelele Facturi (nrfact, datafact) şi Produse (nrcurent, nrfact, denp, cant,
pret, valoare). Să se adauge 3 înregistrări în tabela părinte, pe prima factura 1 înregistrare, pe a
doua 2 iar pe a treia 3 înregistrări. Să se execute cele două proceduri care numără produsele
(prima procedură care necesită ca parametru numărul facturii iar cea de-a doua care afişează
automat pentru toate facturile numărul produselor).

S-ar putea să vă placă și