Sunteți pe pagina 1din 19

17.11.

2022

ACADEMIA DE STUDII ECONOMICE BUCUREŞTI


FACULTATEA DE CIBERNETICĂ, STATISTICĂ ŞI INFORMATICĂ ECONOMICĂ

SGBD Oracle

LIMBAJUL PL/SQL
Gestiunea subprogramelor

BUCUREŞTI
2022-2023

Conf.univ.dr. IULIANA BOTHA (ȘIMONCA)

Subprograme în PL/SQL
 Sunt module de program care îndeplinesc o serie de acţiuni
 Pot fi îmbinate pentru a se obţine subprograme complexe
 Pot fi create:
 La nivel de schemă – subprograme de sine stătătoare
 În interiorul pachetelor de subprograme
 În interiorul unui bloc PL/SQL

1
17.11.2022

Blocuri anonime vs. subprograme


Blocuri anonime Subprograme
Blocuri PL/SQL fără nume Blocuri PL/SQL denumite

Compilate la fiecare rulare Compilate doar o dată (eventual recompilate


dacă se efectuează modificări în corpul
acestora)
Nu sunt stocate în baza de date Stocate în baza de date

Nu pot fi invocate de alte aplicaţii Pot fi invocate de alte aplicaţii prin numele
asociat
Nu returnează valori Funcţiile returnează întotdeauna o valoare.
Şi unele proceduri pot returna valori prin
parametrii de ieşire
Nu pot avea parametri Pot avea parametri

Subprograme în PL/SQL
Secţiuni:
 Declarativă
 Executabilă
 Pentru tratarea excepţiilor
Tipuri de subprograme:
 Proceduri – efectuează acţiuni; pot returna valori prin parametri
de tip IN OUT sau OUT
 Funcţii – de obicei returnează o singură valoare. Dacă sunt
îndeplinite o serie de condiţii, pot fi utilizate în comenzile SQL ca
funcţii de sine stătătoare
Parametri
 IN
 OUT
 IN OUT

2
17.11.2022

Subprograme în PL/SQL
Avantaje:
 codul sursă este mai uşor de întreţinut

 odată ce subprogramul a fost compilat, codul este reutilizabil


 sporesc performanţa

 contribuie la securitatea aplicaţiilor

 modificările necesare se realizează într-un singur loc


 pot fi utilizate de mai mulţi utilizatori simultan

PROCEDURI

3
17.11.2022

Subprograme în PL/SQL
Proceduri

Creare procedură:
CREATE [OR REPLACE] PROCEDURE nume_proc
[(param1 [IN | OUT | IN OUT] TIP_DATA1, ....) ]
-- tipul variabilelor este precizat fără dimensiune
(ex: NUMBER sau VARCHAR2)
IS | AS
-- zona de declarare a variabilelor utilizate
-- NU se utilizează DECLARE
BEGIN
----
[EXCEPTION]
------
END [nume_proc];

Subprograme în PL/SQL
Proceduri

Apel procedură:

1.prin nume dintr-un bloc PL/SQL anonim sau din alt subprogram
2.prin apel direct utilizând:
EXECUTE nume_proc;
 comandă SQL Plus care include apelul într-un bloc PL/SQL anonim
(BEGIN...END;)
 utilizează mai puţină memorie decât CALL
3.prin apel direct utilizând:
CALL nume_proc;
 comandă SQL
 poate inhiba propagarea excepţiilor
4.dintr-o altă aplicaţie (ex. Oracle Forms, Oracle APEX, Oracle JDeveloper,
JAVA)
8

4
17.11.2022

Subprograme în PL/SQL
Proceduri

 Parametrii unei proceduri

IN transmite procedurii o valoare constantă


OUT transmite o valoare către mediul apelant
IN OUT transmite o valoare procedurii şi o altă valoare
mediului apelant prin acelaşi parametru

Subprograme în PL/SQL
Proceduri

Parametri formali: variabile locale declarate în lista parametrilor indicată în


definiţia subprogramului

CREATE PROCEDURE mareste_salariu(p_id IN NUMBER, p_sal IN NUMBER)


IS
BEGIN ...
END mareste_salariu;

Parametri actuali: literali, variabile sau expresii utilizate în lista parametrilor


indicată la apelul subprogramului

id_ang:= 100;
mareste_salariu(id_ang, 2000);

parametrii formali şi cei actuali trebuie să aibă tipuri de date compatibile


parametrii actuali sunt asociaţi celor formali pe parcursul execuţiei
subprogramului
10

5
17.11.2022

Subprograme în PL/SQL
Proceduri

CREATE OR REPLACE PROCEDURE mareste_salariu


(p_id_ang IN angajati.id_angajat%TYPE,
p_proc IN NUMBER)
IS
BEGIN
UPDATE angajati
SET salariul = salariul * (1 + p_proc/100)
WHERE id_angajat = p_id_ang;
END mareste_salariu;
/

EXECUTE mareste_salariu(176,10);

11

Subprograme în PL/SQL
Proceduri

CREATE OR REPLACE PROCEDURE info_angajat


(p_id_ang IN angajati.id_angajat%TYPE,
p_nume OUT angajati.nume%TYPE,
p_sal OUT angajati.salariul%TYPE) IS
BEGIN
SELECT nume, salariul INTO p_nume, p_sal
FROM angajati
WHERE id_angajat = p_id_ang;
END info_angajat;
/
DECLARE
v_nume angajati.nume%TYPE;
v_sal angajati.salariul%TYPE;
BEGIN
info_angajat(171, v_nume, v_sal);
END;
12

6
17.11.2022

Subprograme în PL/SQL
Proceduri

CREATE OR REPLACE PROCEDURE prelucreaza_angajati


IS
CURSOR c_ang IS
SELECT id_angajat
FROM angajati;
BEGIN
FOR rec_ang IN c_ang
LOOP
mareste_salariu(rec_ang.id_angajat, 10);
END LOOP;
COMMIT;
END prelucreaza_angajati;
/

EXECUTE prelucreaza_angajati;

13

Subprograme în PL/SQL
Proceduri

CREATE OR REPLACE PROCEDURE valoare_comenzi


(p_id_client IN comenzi.id_client%TYPE)
IS
v_val NUMBER;
BEGIN
SELECT SUM(r.pret*r.cantitate) INTO v_val
FROM rand_comenzi r,comenzi c
WHERE r.nr_comanda=c.nr_comanda
AND c.id_client=p_id_client;
DBMS_OUTPUT.PUT_LINE('Valoare totala = '||v_val);
END;
/

EXECUTE valoare_comenzi(109); -- apel folosind EXECUTE


BEGIN -- apel în bloc anonim
valoare_comenzi(109);
END;
/

7
17.11.2022

Subprograme în PL/SQL
Proceduri

CREATE OR REPLACE PROCEDURE valoare_comenzi_o


(p_id_client IN comenzi.id_client%TYPE, p_val OUT NUMBER)
IS
BEGIN
SELECT SUM(r.pret*r.cantitate) INTO p_val
FROM rand_comenzi r,comenzi c
WHERE r.nr_comanda=c.nr_comanda
AND c.id_client=p_id_client;
END;
/
DECLARE
n NUMBER;
BEGIN
valoare_comenzi_o(109,n);
DBMS_OUTPUT.PUT_LINE('Valoare: '||n);
END;
/

Subprograme în PL/SQL
Proceduri

 Ştergerea unei proceduri:


DROP PROCEDURE nume_proc;

 Vizualizarea procedurilor în dicţionarul de date:


SELECT object_name FROM user_objects
WHERE object_type='PROCEDURE';

 vizualizarea corpului unei proceduri:


SELECT text FROM user_source
WHERE name='ADAUGA_DEP';

16

8
17.11.2022

Exercițiul 1
CREATE OR REPLACE PROCEDURE afiseaza_produse
IS
CURSOR c IS SELECT * FROM produse;
v c%rowtype;
BEGIN
OPEN c;
LOOP
FETCH c INTO v;
EXIT WHEN c%notfound;
DBMS_OUTPUT.PUT_LINE('Produsul '||v.denumire_produs||' -
categoria: '||v.categorie);
END LOOP;
CLOSE c;
END;
/

--apel
EXECUTE afiseaza_produse;

17

Exercițiul 2
CREATE OR REPLACE PROCEDURE produse_in_categorie
IS
CURSOR c IS
SELECT categorie, COUNT(id_produs) nr_produse
FROM produse
GROUP BY categorie;
BEGIN
FOR v IN c LOOP
DBMS_OUTPUT.PUT_LINE('Categoria: '||v.categorie||' contine:
'||v.nr_produse||' produse.');
END LOOP;
END;
/

--apel
EXECUTE produse_in_categorie;

18

9
17.11.2022

FUNCȚII

19

Gestiunea subprogramelor
Funcţii

Creare funcţie:

CREATE [OR REPLACE] FUNCTION nume_functie


[(param1 [IN] TIP_DATA1,....)]
RETURN TIP_DATA
-- tipul variabilelor este precizat fără dimensiune
(ex: NUMBER sau VARCHAR2)
IS | AS
-- zona de declarare a variabilelor utilizate în subprogram
-- NU se utilizează DECLARE
BEGIN
----
RETURN valoare;
[EXCEPTION]
------
END [nume_functie];
/

20

10
17.11.2022

Gestiunea subprogramelor
Funcţii

Apel funcţie:

1. într-un bloc PL/SQL anonim sau în alt subprogram


DECLARE v TIP_DATA;
BEGIN
v := nume_functie(param_actual); ...
END;

2. ca parametru al unui alt subprogram


EXECUTE DBMS_OUTPUT.PUT_LINE(nume_functie(param_actual));

3. într-o comandă SQL (nu întotdeauna)

21

Gestiunea subprogramelor
Funcţii

CREATE OR REPLACE FUNCTION afiseaza_salariul


(p_id angajati.id_angajat%TYPE) RETURN NUMBER IS
p_sal angajati.salariul%TYPE := 0;
BEGIN
SELECT salariul INTO p_sal
FROM angajati
WHERE id_angajat = p_id;
RETURN p_sal;
END afiseaza_salariul;
/

22

11
17.11.2022

Gestiunea subprogramelor
Funcţii

DECLARE --apel intr-un bloc anonim


v_sal angajati.salariul%TYPE;
BEGIN
v_sal := afiseaza_salariul (100);
DBMS_OUTPUT.PUT_LINE('Salariul este: '||v_sal);
END;
/
--apel ca parametru al unui subprogram
EXECUTE DBMS_OUTPUT.PUT_LINE(afiseaza_salariul(100))
/
--apel intr-o comanda SQL
SELECT id_functie, afiseaza_salariul(id_angajat) AS salariu
FROM angajati;
/

23

Exercițiul 1
/*functie care verifica daca salariul angajatului indicat este mai
mare decat salariul mediu al angajatilor din departamentul in care
acesta lucreaza*/
CREATE OR REPLACE FUNCTION verifica_sal_p
(p_id_ang angajati.id_angajat%TYPE)
RETURN Boolean IS
v_id_dep angajati.id_departament%TYPE;
v_sal angajati.salariul%TYPE;
v_sal_mediu angajati.salariul%TYPE;
BEGIN
SELECT salariul, id_departament INTO v_sal, v_id_dep
FROM angajati WHERE id_angajat=p_id_ang;
SELECT avg(salariul) INTO v_sal_mediu FROM angajati
WHERE id_departament=v_id_dep;
IF v_sal > v_sal_mediu THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL; 24
END;
/

12
17.11.2022

Exercițiul 1
--apel in bloc anonim
DECLARE
v_id angajati.id_angajat%TYPE:=&v;
BEGIN
DBMS_OUTPUT.PUT_LINE('Verificare angajat '||v_id);
IF (verifica_sal_p(v_id) IS NULL) THEN
DBMS_OUTPUT.PUT_LINE('Exceptie!');
ELSIF (verifica_sal_p(v_id)) THEN
DBMS_OUTPUT.PUT_LINE('salariul > salariul mediu');
ELSE
DBMS_OUTPUT.PUT_LINE('salariul < salariul mediu');
END IF;
END;
/

25

Gestiunea subprogramelor
Funcţii

 O funcţie PL/SQL poate fi apelată într-o comandă SQL dacă:


 primește numai parametri IN având tipuri de date SQL
 returnează tipuri de date SQL
 nu conţine comenzile COMMIT sau ROLLBACK
 atunci când este utilizată în interogări asupra unei tabele, nu
conţine comenzi INSERT, UPDATE sau DELETE
 atunci când este utilizată în comenzi UPDATE sau DELETE pe o
tabelă, nu conţine comenzi de manipulare a aceleiaşi tabele
 nu conţine comenzi de definire a datelor sau de control al
datelor (prin intermediul EXECUTE IMMEDIATE) – pentru că
presupun COMMIT implicit
 nu conține apeluri de subprograme care încalcă restricțiile de
mai sus

13
17.11.2022

Exercițiul 2
/* functii care returneaza contributiile si salariul
net, pe baza salariului brut*/
CREATE OR REPLACE FUNCTION cas(p_brut IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (p_brut * 0.25);
END cas;
/

CREATE OR REPLACE FUNCTION cass(p_brut IN NUMBER)


RETURN NUMBER IS
BEGIN
RETURN (p_brut * 0.10);
END cass;
/
27

Exercițiul 2
CREATE OR REPLACE FUNCTION imp(p_brut IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN ((p_brut-cass(p_brut)-cas(p_brut)) * 0.10);
END imp;
/

CREATE OR REPLACE FUNCTION net(p_brut IN NUMBER)


RETURN NUMBER IS
BEGIN
RETURN (p_brut-cas(p_brut)-cass(p_brut)-imp(p_brut));
END net;
/

28

14
17.11.2022

Exercițiul 2
--apelul intr-o comanda SQL
SELECT id_angajat, nume, salariul, net(salariul)
FROM angajati
ORDER BY id_angajat;

29

Gestiunea subprogramelor
Funcţii

 O funcţie PL/SQL acționează ca o funcție single-row și poate


apărea în următoarele clauze ale comenzilor SQL:
 SELECT
 WHERE și HAVING ale unei interogări (în condiții)
 CONNECT BY, START WITH, ORDER BY și GROUP BY ale unei
interogări
 VALUES dintr-o comandă INSERT
 SET dintr-o comandă UPDATE

15
17.11.2022

Gestiunea subprogramelor
Funcţii

--apelul functiei net intr-o comanda SQL

SELECT id_angajat, net(salariul)


FROM angajati
WHERE net(salariul)> (SELECT MAX(net(salariul))
FROM angajati
WHERE id_departament=30)
ORDER BY net(salariul) DESC;

Gestiunea subprogramelor
Funcţii
/*functie care genereaza eroare la apelul intr-o comanda LMD
din cauza faptului ca include deja o astfel de comanda*/
CREATE OR REPLACE FUNCTION test_call_sql(p_sal NUMBER)
RETURN NUMBER IS
BEGIN
INSERT INTO angajati(id_angajat, nume,
email, data_angajare, id_functie, salariul)
VALUES(1, 'Frost', 'jfrost@company.com',SYSDATE,
'SA_MAN', p_sal);
RETURN (p_sal + 100);
END test_call_sql;
/

UPDATE angajati
SET salariul = test_call_sql(2000)
WHERE id_angajat = 170;
Error report -
SQL Error: ORA-04091: table IULI.ANGAJATI is mutating, trigger/function
may not see it
ORA-06512: at "IULI.TEST_CALL_SQL", line 4 32

16
17.11.2022

Subprograme în PL/SQL
Funcţii

 Ştergerea unei funcţii:


DROP FUNCTION nume_fct;

 Vizualizarea funcţiilor în dicţionarul de date:


SELECT object_name FROM user_objects
WHERE object_type='FUNCTION';

 Vizualizarea corpului unei funcţii:


SELECT text FROM user_source
WHERE name='VERIFICA_SAL';

33

Gestiunea subprogramelor
PROCEDURI FUNCŢII
Apelate direct prin nume Apelate ca parte a unei expresii

Nu conţin clauza RETURN în Trebuie să conţină clauza RETURN


antet în antet

Pot returna valori prin Trebuie să returneze o valoare


parametrii de ieşire
Pot conţine comanda RETURN Trebuie să conţină cel puţin o comandă
fără indicarea unei valori RETURN

34

17
17.11.2022

Să se rezolve!
Construiți procedura AfisareAngajati prin care să se afișeze informații
despre angajații din departamentul al cărui id este specificat drept
parametru de intrare.
Apelați procedura.

35

Să se rezolve!
Construiți funcția Vechime care să returneze vechimea angajatului al
cărui id este specificat drept parametru de intrare.
Apelați funcția în cadrul unui bloc anonim.

36

18
17.11.2022

Să se rezolve!
Construiți funcția Calcul_cantitate_totala care să returneze cantitatea
totală comandată dintr-un produs al cărui id este specificat drept
parametru de intrare.
Apelați funcția în cadrul unui bloc anonim.

37

CURSUL 9...

Recapitulare

19

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