Sunteți pe pagina 1din 8

Facultatea de Cibernetică, Statistică şi Informatică Economică

SGBD Oracle – seminarul 7

Subprograme PL/SQL

 Blocuri PL/SQL care au nume;


 Pot fi proceduri sau funcții;
 Se pot stoca la nivel de Oracle Server (proceduri/functii stocate) sau de aplicație (APEX,
Developer Suite);
 Se pot grupa in pachete de programe (PACKAGE);
 Variabilele declarate in zona declarativa a procedurii se numesc parametri formali (formal
parameters). Pentru acestia se pot specifica valori implicite (DEFAULT) ;
 Variabilele utilizate in apelul procedurii/funcției se numesc parametri actuali (actual
parameters);
 Când procedura/funcția e apelata, variabilele din procedura sunt incarcate cu valorile
variabilelor definite in zona declarativa a blocului anonim;
 In corpul procedurilor/functiilor nu se pot utiliza variabile globale sau de substitutie, acestea vor
fi transmise in subprograme cu ajutorul parametrilor;
 Pentru afisarea erorilor aparute la compilare se utilizează SHOW ERRORS.

1. PROCEDURI
Parametrii utilizati in procedura (parametri formali) pot fi de tip:
 IN (valoarea parametrului actual este transferata in variabila definita in procedura.
Aceasta variabila este considerata read-only). Când procedura se încheie, controlul
revine mediului apelant. Parametrul actual nu se modifica. Este modul implicit;
 OUT (valoarea parametrului formal este transferata in parametrul actual când procedura
se incheie);
 IN OUT (valorile sunt transferate de la un tip de variabilă la celălalt (la lansarea în
execuţie/terminarea procedurii)).
 un parametru IN poate apare numai în partea dreapta a (:=)
 un parametru OUT poate apare numai în partea stânga a (:=)
 un parametru IN OUT poate apare în ambele părţi ale (:=)

Sintaxa pentru crearea unei proceduri:


CREATE [OR REPLACE] PROCEDURE NUME_PROC
[(param1 [IN|OUT|IN OUT] TIP1,
Param2[IN|OUT|IN OUT] TIP2, ....) ]
-- tipul variabilelor este precizat fara dimensiune (ex: NUMBER sau VARCHAR2)
IS|AS
-- zona de declarare a variabilelor utilizate in subprogram
-- NU se utilizeaza explicit DECLARE
BEGIN
----
[EXCEPTION]
------
END [NUME_PROC];

Pentru a sterge procedura:

1
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

DROP PROCEDURE NUME_PROC;


Apelul unei proceduri se poate realiza in urmatoarele moduri:
 prin nume dintr-un bloc PL/SQL anonim sau din alt subprogram;
 prin apel direct cu EXECUTE nume_proc sau EXEC nume_proc sau CALL nume_proc.
Chiar dacă de cele mai multe ori, CALL și EXECUTE/EXEC sunt folosite interschimbabil,
există anumite diferențe:
o EXEC/EXECUTE este o comandă SQL*PLUS care include subprogramul apelat
într-un bloc anonim BEGIN… END. De obicei, un apel folosind EXEC necesită mai
puțină memorie comparativ cu un apel folosind CALL. Observație: SQL*PLUS este
o interfață cu utilizatorul specifică Oracle, a nu se confunda cu limbajul SQL.
o CALL este o comanda SQL și poate folosi doar tipuri de date SQL. Are clauza INTO
care poate fi folosită pentru a specifica variabila de mediu (HOST) care va prelua
valoarea returnată de către o funcție. Un apel folosind CALL poate inhiba
propagarea unor excepții către mediu. CALL poate fi folosit în cadrul
declanșatorilor, în locul corpului acestora, pentru a apela o altă procedură.
 din alt mediu Oracle (APEX, Oracle Developer Suite)

Parametrii de tip IN

Exemplu: Procedura modifica_salariul primeşte doi parametrii: p_id_angajat şi procent şi


majorează cu procentul specificat salariul angajatului cu id_angajat=p_id_angajat:
CREATE OR REPLACE
PROCEDURE modifica_salariul_procent
(p_id_angajat IN angajati.id_angajat%type, procent IN number)
IS
v_salariul angajati.salariul%type;
BEGIN
Select salariul into v_salariul from angajati where id_angajat=p_id_angajat;
dbms_output.put_line('Angajatul are salariul de '||v_salariul);
Update angajati
Set salariul=salariul*(1+procent/100)
Where id_angajat=p_id_angajat;
Select salariul into v_salariul from angajati where id_angajat=p_id_angajat;
Dbms_output.put_line('Angajatul are acum salariul de '||v_salariul);
END;
/
show errors;
O procedură poate fi rulată folosind EXECUTE, CALL sau dintr-un alt bloc PL/SQL.
SQL> CALL modifica_salariul_procent(176, 10)
SQL> EXECUTE modifica_salariul_procent(176, 10)
Rularea cu EXECUTE este echivalentă cu:
begin
modifica_salariul_procent(176, 10);
end;
/

Parametrii de tip OUT

2
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

Exemplu: Procedura primeşte ca parametru de tip IN id_ul unui angajat şi returnează prin
parametrii de tip OUT numele şi salariul acestuia:
CREATE OR REPLACE PROCEDURE cauta_angajat
(p_id_angajat IN angajati.id_angajat%type,
p_nume OUT angajati.nume%type,
p_salariul OUT angajati.salariul%type)
IS
BEGIN
Select nume, salariul into p_nume, p_salariul from angajati where
id_angajat=p_id_angajat;
DBMS_OUTPUT.PUT_LINE(' Angajatul '||p_nume||' are salariul de: '||p_salariul);
END;
/
In această situație nuvom folosi un bloc apelator anonim:
SET SERVEROUTPUT ON
DECLARE
v_nume angajati.nume%type;
v_salariul angajati.salariul%type;
BEGIN
Cauta_angajat(150, v_nume, v_salariul);
END;
/

Exemplu: Procedura calculează salariul mediu şi îl returnează printr-un parametru de tip OUT:

CREATE or REPLACE PROCEDURE sal_mediu


(p_sal_mediu OUT number)
IS
BEGIN
Select AVG(salariul) into p_sal_mediu from angajati;
END;
/
show errors;

Vom apela procedura folosind EXECUTE și o variabilă de mediu (HOST):

VARIABLE v_sal_mediu NUMBER


EXECUTE sal_mediu(:v_sal_mediu)
Print v_sal_mediu

Parametrii de tip IN OUT

Exemplu: Procedura modifică salariul unui angajat doar în cazul în care este mai mic decât media
prin apelarea procedurii create mai sus, MODIFICA_SALARIUL_PROCENT. Procedura primeşte
id-ul angajatului ca parametru de intrare şi salariul mediu actual şi prin returnează prin parametrul
de tip IN OUT salariul mediu modificat prin apelul procedurii SAL_MEDIU.

CREATE or REPLACE PROCEDURE modifica_salariul_med


(p_id_angajat IN angajati.id_angajat%type, p_sal_mediu IN OUT number)

3
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

IS
nume angajati.nume%type;
sal angajati.salariul%type;
BEGIN
Select nume, salariul into nume, sal from angajati where id_angajat= p_id_angajat;
IF sal<p_sal_mediu then
MODIFICA_SALARIUL_PROCENT (p_id_angajat, 15);
END IF;
SAL_MEDIU (p_sal_mediu);
End;
/

Apelul procedurii intr-un bloc anonim:


SET SERVEROUTPUT ON
DECLARE
v_id_angajat angajati.id_angajat%type;
v_nume angajati.nume%type;
v_salariul angajati.salariul%type;
v_sal_mediu number;
BEGIN
--apelul cu id valid =105
v_id_angajat:=105;

--apelul procedurii pentru vizualizarea datelor angajatului


CAUTA_ANGAJAT(v_id_angajat, v_nume, v_salariul);

--apelul procedurii pentru aflarea salariului mediu. La afisare, se va rotunji la 2 zecimale


SAL_MEDIU (v_sal_mediu);
DBMS_OUTPUT.PUT_LINE('Salariul mediu este acum: '||round(v_sal_mediu,2));

--apelul procedurii pentru modificarea salariului


modifica_salariul_med (v_id_angajat, v_sal_mediu);
CAUTA_ANGAJAT(v_id_angajat, v_nume, v_salariul);

--apelul cu id invalid
v_id_angajat:=1230;
CAUTA_ANGAJAT(v_id_angajat, v_nume, v_salariul);
modifica_salariul_med (v_id_angajat, v_sal_mediu);

Exception
When NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('Angajat inexistent! ID invalid');
END;
/
rollback;

Stergerea unei proceduri se realizeaza prin comanda:


DROP PROCEDURE nume_procedura;

4
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

Vizualizarea procedurilor in dictionarul metadatelor se realizeaza prin:


Select object_name
From user_objects
Where object_type='PROCEDURE';

Iar pentru a vizualiza corpul procedurii:


Select text
From user_source
Where name='NUME_PROC' and type='PROCEDURE';

2. FUNCŢII:

Sintaxa pentru crearea unei functii:


CREATE [OR REPLACE] FUNCTION nume_functie
[(param1 [IN/OUT/IN OUT] TIP1,
Param2[IN/OUT/IN OUT] TIP2, ....) ]
RETURN TIP_DATA
-- tipul variabilelor este precizat fara dimensiune (ex: NUMBER sau VARCHAR2)
IS|AS
-- zona de declarare a variabilelor utilizate in subprogram
-- nu se utilizeaza DECLARE
BEGIN
----
RETURN VALOARE;
[EXCEPTION]
------
END [NUME_FUNCTIE];

Pentru vizualizarea tipului returnat se utilizeaza:


DESCRIBE nume_functie;

Pentru a sterge functia:


DROP FUNCTION nume_functie;

Observație: Funcțiile pot avea parametrii OUT și IN/OUT, acestea însă nu vor putea fi folosite în
expresii SQL. Vor putea fi însă apelate din alte blocuri PL/SQL.

Exemplu: Funcția verifica_salariul returnează TRUE/FALSE daca salariatul are salariul mai
mare/mai mic sau egal cu salariul mediu si NULL daca salariatul nu exista

CREATE OR REPLACE FUNCTION verifica_salariul


(p_id_angajat IN angajati.id_angajat%type, p_sal_mediu IN number)
RETURN Boolean
IS
v_salariul angajati.salariul%type;
BEGIN
SELECT salariul into v_salariul from angajati where id_angajat=p_id_angajat;
IF v_salariul > p_sal_mediu then
return true;
5
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

ELSE
return false;
end if;
EXCEPTION
WHEN no_data_found THEN
return NULL;
end;
/
show errors

Vizualizarea tipului returnat:


describe verifica_salariul;
Funcția nu poate fi apelată folosind CALL INTO deoarece returnează BOOLEAN. Nu putem
declara o variabilă de mediu de acest tip.

variable v boolean
Error! Usage: VAR[IABLE] [ <variable> [ NUMBER | CHAR | CHAR (n [CHAR|
BYTE]) |
VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |
NVARCHAR2 (n) | CLOB | NCLOB | REFCURSOR |
BINARY_FLOAT | BINARY_DOUBLE ] ]
where n is a positive integer
call verifica_salariul(110,5000) into :v
SQL Error: ORA-01008: nu toate variabilele au fost legate
01008. 00000 - "not all variables bound"

Apelul funcției dintr-un bloc anonim:

SET SERVEROUTPUT ON

DECLARE
v_sal_mediu number;
BEGIN
--apelul procedurii pentru calculul salariului mediu:
SAL_MEDIU (v_sal_mediu);

--primul apel al functiei

IF (verifica_salariul(11, v_sal_mediu) IS NULL) then


dbms_output.put_line('Angajat cu ID invalid!');
elsif (verifica_salariul(11, v_sal_mediu)) then
dbms_output.put_line('Salariatul are salariul mai mare decat media!');
else
dbms_output.put_line(' Salariatul are salariul mai mic decat media!');
end if;

--al doilea apel


IF (verifica_salariul(110, v_sal_mediu) IS NULL) then
dbms_output.put_line('Angajat cu ID invalid!');
elsif (verifica_salariul(110, v_sal_mediu)) then
dbms_output.put_line('Salariatul are salariul mai mare decat media!');
6
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

else
dbms_output.put_line(' Salariatul are salariul mai mic decat media!');
end if;

--al treilea apel


IF (verifica_salariul(104, v_sal_mediu) IS NULL) then
dbms_output.put_line('Angajat cu ID invalid!');
elsif (verifica_salariul(104, v_sal_mediu)) then
dbms_output.put_line('Salariatul are salariul mai mare decat media!');
else
dbms_output.put_line(' Salariatul are salariul mai mic decat media!');
end if;
END;
/

Utilizarea functiilor PL/SQL in expresii SQL

Exemplu:
CREATE OR REPLACE FUNCTION TAXA (value IN NUMBER, proc IN
NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (value*proc/100);
END taxa;
/

--apelul funcţiei
SELECT id_produs, cantitate, pret, taxa (pret, 20) as tva
FROM rand_comenzi;

Apel folosind EXECUTE:

VARIABLE rezultat NUMBER


EXECUTE :rezultat:=taxa(100,20)
PRINT rezultat

Apel din SQL folosind DUAL:

SELECT TAXA(100,20) FROM DUAL;

Pot fi utilizate in toate clauzele SELECT:

Exemplu:
SELECT id_produs, cantitate, pret, taxa (pret, 20)
FROM rand_comenzi
WHERE taxa(pret, 20)>(select avg(taxa(pret, 20)) from rand_comenzi)
ORDER BY taxa(pret, 20) DESC;

Observatii!

7
Facultatea de Cibernetică, Statistică şi Informatică Economică
SGBD Oracle – seminarul 7

Functiile utilizate in expresii SQL trebuie sa accepte doar parametrii de tip IN si sa returneze numai
tipuri de date specifice PL/SQL. Acestea nu trebuie sa contina comenzi DML (update, delete,
insert) sau comenzi DDL si nici comenzi pentru controlul tranzactiilor (commit, rollback) si nici nu
trebuie sa apeleze alte subprograme care sa incalce aceste restrictii.
Functiile apelate in cadrul expresiilor SQL pot fi continute in pachete.

Exemplu: Apelul urmatoarei functii dintr-o instructiune SQL va returna o eroare: ORA-
04091: table [nume_tabela] is mutating, trigger/function may not see it
CREATE OR REPLACE FUNCTION produs_nou (pret_min NUMBER)
RETURN NUMBER
IS
BEGIN
INSERT INTO produse values (1, 'cafea', 'kg', pret_min);
RETURN (pret_min+100);
END;
/
Apelul din instrucțiuni SQL:
UPDATE produse
SET pret_min= produs_nou(2000)
WHERE id_produs=111;

Ștergerea unei functii se realizeaza utilizand comanda:


DROP FUNCTION nume_functie;

Vizualizarea functiilor in dictionarul metadatelor se realizeaza prin:


Select object_name
From user_objects
Where object_type='FUNCTION';

Pentru a vizualiza corpul functiei:


Select text
From user_source
Where name='NUME_FUNCTIE' and type=' FUNCTION '
ORDER BY line;

Exemplu:
Select text
From user_source
Where name='TAXA' and type='FUNCTION'
ORDER BY line;

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