Sunteți pe pagina 1din 748

Tehnici de programare cu baze de

date

#1 PL/SQL
Concepte generale

Adrian Runceanu
www.runceanu.ro/adrian
2022
copyright@www.adrian.runceanu.ro

Câteva precizări

Structura cursului

◦ 2 ore curs – titular curs:


Sef lucr. dr. Adrian Runceanu
◦ 2 ore laborator – titular aplicaţii practice:
Sef lucr. dr. Adrian Runceanu

Tehnici de programare cu baze de date


copyright@www.adrian.runceanu.ro

Câteva precizări
Procentaje evaluare Forme de examinare:

30  Examen final (verificare)


– 60%
60
10  Activitate la curs si
laborator – 10%
 Verificare finală lucrări
Evaluare pe parcursul
semestrului de laborator – 30%

Tehnici de programare cu baze de date


copyright@www.adrian.runceanu.ro

Câteva precizări
Bibliografia necesară cursului:
1. Abiteboul S. etc:”Foundations of Databases”, Addison Wesley,
95
2. Date C.J.”:An Introduction to Database Systems, ed.8, Addison
Wesley, 2004
3. Fotache M. etc. :“Oracle 9i – Ghidul dezvoltarii aplicatiilor
profesionale”, Polirom, 2003
4. Garcia-Molina H., Ullman J.D. :“Database Systems.The Complete
Book”, 2000
5. Popescu Ileana: “Modelarea bazelor de date”, Editura Tehnica,
Bucuresti, 2000
6. Felea V. :”Elemente ale implementarii modelului relational in
sisteme de gestiune de baze de date”. Ed.MatrixROM, 2007
7. Felea V., Matei C. si Balta M.:”Interogarea bazelor de date.
Aplicatii in Oracle si SQL Server”, Ed.MatrixROM, 2005
Referinţe electronice:
 http://thor.info.uaic.ro/~felea/
 Documentatia produselor Oracle

Tehnici de programare cu baze de date


copyright@www.adrian.runceanu.ro

Câteva precizări
1) Hub-ul colaborativ Microsoft Teams: cursul
FI-3-Tehnici de programare cu baze de date-
2022-2023 va contine toate cursurile si
laboratoarele.

2) Suport curs - varianta electronică disponibilă


pe site-ul: www.runceanu.ro/adrian
Notă: Actualizarea site-ului se face saptamnal.

Tehnici de programare cu baze de date


copyright@www.adrian.runceanu.ro

Tehnici de programare cu
baze de date

Concepte generale

6
copyright@www.adrian.runceanu.ro

GENERALITĂŢI DESPRE BAZE DE DATE

 Baza de date este un ansamblu


structurat de date coerente, fără
redundanţă inutilă, astfel încât acestea
pot fi prelucrate eficient de mai mulţi
utilizatori într-un mod concurent.
copyright@www.adrian.runceanu.ro

GENERALITĂŢI DESPRE BAZE DE DATE

 Un sistem de gestiune al bazei de


date (SGBD – Data Base Management
System) este un produs software cu
elemente hardware, care asigură
interacţiunea cu o bază de date,
permiţând definirea, consultarea şi
actualizarea datelor din baza de date.
copyright@www.adrian.runceanu.ro

GENERALITĂŢI DESPRE BAZE DE DATE

 Un sistem de gestiune al bazei de


date (SGBD – Data Base Management
System) este un produs software care
asigură interacţiunea cu o bază de
date, permiţând definirea, consultarea
şi actualizarea datelor din baza de date.
copyright@www.adrian.runceanu.ro

PL/SQL
 Procedural Language/Structured Query
Language (PL/SQL) este extensia
procedurală a limbajului SQL.
 PL/SQL este un limbaj de programare
sofisticat care asigură accesarea datelor unei
baze de date relaţionale orientate obiect şi
permite gruparea unei mulţimi de comenzi
într-un bloc unic de tratare a datelor.
 Programul este format din unul sau mai multe
blocuri care pot conţine blocuri imbricate.
copyright@www.adrian.runceanu.ro

PL/SQL include:
1. instrucţiuni SQL pentru manipularea
datelor şi pentru gestiunea tranzacţiilor
2. instrucţiuni proprii
 Limbajul combină construcţiile
procedurale ale unui limbaj de generatia
3 (LG3) cu puterea şi flexibilitatea lui
SQL (LG4).
 Combinaţia a generat un limbaj puternic
pentru modelarea aplicaţiilor complexe.
copyright@www.adrian.runceanu.ro

PL/SQL extinde SQL prin construcţii


specifice limbajelor procedurale:
◦ definirea variabilelor
◦ declararea tipurilor
◦ utilizarea structurilor de control
◦ implementarea procedurilor şi funcţiilor
◦ introducerea tipurilor obiect şi a metodelor, etc.
PL/SQL oferă posibilităţi moderne de
tratare a informaţiei:
◦ încapsularea datelor
◦ analiza specială a erorilor
◦ mascarea informaţiei
◦ orientarea obiect
copyright@www.adrian.runceanu.ro

Posibilităţile lui SQL sunt


folosite pentru un acces rafinat la
date, iar facilităţile oferite de
PL/SQL sunt folosite pentru fluxul
controlului procesării datelor.
copyright@www.adrian.runceanu.ro

Dintre funcţionalităţile limbajului


PL/SQL care determină ca acesta să fie
frecvent utilizat se remarcă următoarele
facilităţi:
1. integrarea comenzilor SQL de bază
2. integrarea cu server-ul Oracle şi cu
aplicatii Oracle
3. oferirea unui suport pentru
programarea orientată obiect
4. asigurarea securităţii informaţiei
5. definirea şi gestiunea blocurilor de
instrucţiuni
copyright@www.adrian.runceanu.ro

6. gestiunea variabilelor, constantelor şi a


cursoarelor
7. modularizarea programelor
(subprograme, pachete)
8. implementarea şi utilizarea
declanşatorilor
9. utilizarea structurilor de control
fundamentale
10. detectarea şi gestiunea erorilor de
execuţie şi a situaţiilor excepţionale
11. dezvoltarea de aplicaţii Web
copyright@www.adrian.runceanu.ro

 PL/SQL este o tehnologie utilizată de server-ul


Oracle şi de anumite aplicatii Oracle.

 Blocurile PL/SQL sunt transmise unui motor


PL/SQL şi procesate (compilate şi executate)
de acesta.
 Motorul PL/SQL poate să se afle pe server-ul
Oracle sau într-un utilitar, iar utilizarea sa
depinde de unde se invocă PL/SQL.
 Multe aplicatii Oracle (inclusiv Developer/2000)
au propriul lor motor PL/SQL care este
independent de motorul prezent pe server-ul
Oracle.
copyright@www.adrian.runceanu.ro
 Blocurile PL/SQL pot fi executate:
1. pe staţia client fără interacţiune cu server-ul
2. sau în întregime pe server.
 Când blocurile PL/SQL sunt referite dintr-un
program PRO*, din iSQL*Plus, sau de către
Server Manager, motorul PL/SQL de pe
server-ul Oracle va procesa aceste blocuri.
copyright@www.adrian.runceanu.ro

 Acesta descompune blocul în instrucţiuni


SQL şi le trimite executorului de instrucţiuni
SQL (SQL Statement Executor) de pe server-
ul Oracle.
 Fără PL/SQL, instrucţiunile SQL ar fi
procesate separat, fiecare la un moment dat,
fiecare implicând un apel la server-ul Oracle.
 Restul comenzilor (procedurale) sunt procesate
copyright@www.adrian.runceanu.ro

de către executorul instrucţiunilor procedurale


(PSE – Procedural Statement Executor) care
este în motorul PL/SQL.
 PSE procesează datele care sunt locale
aplicaţiei, reducându-se astfel activitatea de
transfer spre server-ul Oracle şi numărul de
cursoare solicitate.
 În felul acesta, este necesar un singur transfer
pentru a trimite blocul din aplicaţie către server.
copyright@www.adrian.runceanu.ro

O aplicaţie bază de date poate fi


structurată în trei părţi:

1. interfaţa utilizator (utilizatorul introduce


anumite informaţii şi obţine nişte
rezultate în urma executării aplicaţiei)

2. aplicaţia logică efectivă

3. baza de date
copyright@www.adrian.runceanu.ro

Există două modele pentru


proiectarea unei aplicaţii bază de date:

1. modelul client-server (two-tier)

2. modelul three-tier
copyright@www.adrian.runceanu.ro

1. Modelul client-server
 Multe dintre aplicaţiile baze de date sunt
construite folosind modelul clasic client-
server, descris succint anterior pentru
PL/SQL.

 Modelul este caracterizat de cele două


componente:
1. client
2. server
 Client-ul foloseste interfaţa,
 iar server-ul conţine baza de date.
copyright@www.adrian.runceanu.ro

1. Modelul client-server
 Aplicaţia logică este scindată între client
şi server.

 De remarcat din această caracteristică


fundamentală a modelului că aplicaţia
comunică direct cu server-ul.

 Există un motor PL/SQL pe server, iar


în anumite cazuri şi pe client.
copyright@www.adrian.runceanu.ro

 Dacă motorul PL/SQL este pe


server, atunci aplicaţia (care poate
fi scrisă în Pro*C, JDBC, OCI sau
alte limbaje) care rezidă pe client
trimite cereri la un server de date.
 Cererile sunt rezolvate utilizând
SQL.
 Diferite cereri SQL pot fi grupate
într-un bloc PL/SQL şi trimise ca o
singură entitate server-ului.
copyright@www.adrian.runceanu.ro

2. Modelul three-tier
În modelul three-tier interfaţa
utilizator, aplicaţia logică şi baza de
date sunt scindate în trei părţi separate:

1. Client Browser
2. Application Server (Oracle Internet
Application Server – IAS)
3. Oracle Database Server
copyright@www.adrian.runceanu.ro

 Clientul (cel mai frecvent un browser)


apelează subprograme care generează
ca rezultat pagini HTML, iar Application
Server procesează solicitările.
 În Oracle9i, aplicaţiile Forms şi Reports
se execută numai ca parte a unui model
three-tier.
 De exemplu, Oracle Web Forms
permite desfăşurarea unei aplicaţii într-
un mediu multi-tier Internet fără a
modifica o linie de cod.
copyright@www.adrian.runceanu.ro

 În general, comenzile SQL şi PL/SQL sunt


trimise server-ului pentru a fi executate.
 Pentru a realiza acest lucru, trebuie
stabilită conectarea la BD.
 Aceasta presupune ca baza să autentifice
utilizatorul (parolă şi identificator).
 PL/SQL nu conţine o sintaxă pentru
realizarea conectării la baza de date.
 Conectarea poate fi realizată de alte
componente ale sistemului (de exemplu,
iSQL*Plus).
copyright@www.adrian.runceanu.ro

 PL/SQL are un rol important atât la


nivelul server-ului Oracle (prin
subprograme stocate, declanşatori şi
pachete), cât şi la nivelul utilitarelor
Oracle (de exemplu, Developer/2000 –
componenta declanşatori).

 Partea procedurală este atât la nivel de


client, cât şi la nivel de server.

 Cererile însă nu se execută pe staţii


client, ci numai pe server.
copyright@www.adrian.runceanu.ro

PL/SQL constituie fundamentul


pentru realizarea diverselor aplicaţii:
 fişiere iSQL*Plus (script file);
 proceduri şi funcţii stocate (stored
procedure):
1. o procedură sau o funcţie stocată este un
subprogram PL/SQL care poate fi invocat
de o aplicaţie client
2. un declanşator BD
3. un declanşator aplicaţie
copyright@www.adrian.runceanu.ro

1. Declanşatori bază de date (database trigger)


- un declanşator bază de date este un bloc
PL/SQL care se execută la apariţia unui
eveniment:
◦ modificarea unui tabel al bazei
◦ modificarea unei vizualizări
◦ anumite acţiuni sistem
◦ sau chiar anumite acţiuni ale utilizatorului

2. Pachete (package): un pachet este un bloc


PL/SQL care încapsulează într-o unitate logică
în baza de date o mulţime de proceduri, funcţii,
variabile, constante, tipuri, cursoare şi excepţii;
copyright@www.adrian.runceanu.ro

3. Declanşatori aplicaţie (application


trigger) - un declanşator aplicaţie este
un bloc PL/SQL care se execută în
urma unui eveniment provocat de
sistem.
 Aplicaţiile Oracle (Oracle Forms şi
Oracle Reports) sunt dotate cu
motoare PL/SQL care permit
construirea acestor declanşatori.
copyright@www.adrian.runceanu.ro

Portabilitatea PL/SQL
Referitor la portabilitatea limbajului,
pot fi remarcate două aspecte:
1. Aplicaţiile PL/SQL se pot executa pe
orice platformă sau sistem de operare
pe care poate fi executat Oracle.
2. PL/SQL permite transfer de cod între
server-ul Oracle şi aplicaţii. Pot fi
scrise pachete program portabile şi
crea biblioteci ce pot fi utilizate în
diferite situaţii, de diverse aplicaţii.
copyright@www.adrian.runceanu.ro

Controlul execuţiei unui bloc PL/SQL


copyright@www.adrian.runceanu.ro

PL/SQL este un limbaj cu


structură de bloc, adică programele
sunt compuse din blocuri care pot fi
complet separate sau imbricate.

 Structuraunui bloc poate fi obţinută


combinând subprograme, pachete,
blocuri imbricate.

 Blocurile pot fi folosite în utilitarele


Oracle.
copyright@www.adrian.runceanu.ro

Pentru modularizarea unui program este


necesară:
1. gruparea logică a instrucţiunilor în blocuri
2. imbricarea de subblocuri în blocuri mai mari
3. descompunerea unei probleme complexe într-
o mulţime de module logice şi implementarea
acestora cu ajutorul blocurilor
4. plasarea în biblioteci a codului PL/SQL
reutilizabil, de unde poate fi folosit de aplicaţii
5. depunerea codului într-un server Oracle, de
unde este accesibil oricărei aplicaţii care
interacţionează cu baza de date Oracle
copyright@www.adrian.runceanu.ro

Un program PL/SQL poate


cuprinde unul sau mai multe blocuri.
Un bloc poate fi:
1. anonim
2. neanonim
copyright@www.adrian.runceanu.ro

Blocuri anonime
1. Blocurile anonime sunt blocuri PL/SQL
fără nume, care sunt construite dinamic şi
sunt executate o singură dată.
 Acest tip de bloc nu are argumente şi nu
returnează un rezultat.
 Ele sunt declarate într-un punct al
aplicaţiei, unde vor fi executate (trimise
motorului PL/SQL).
 În blocurile anonime pot fi declarate
proceduri şi funcţii PL/SQL.
copyright@www.adrian.runceanu.ro

Blocuri neanonime
2. Blocurile neanonime sunt:

◦ fie blocuri cu nume (etichetate) construite


static sau dinamic şi executate o singură
dată,
◦ fie subprograme, pachete sau declanşatori.
copyright@www.adrian.runceanu.ro

1. Subprogramele sunt proceduri sau


funcţii depuse în baza de date.
 Aceste blocuri sunt executate de mai
multe ori şi, în general, nu mai sunt
modificate după ce au fost construite.
 Procedurile şi funcţiile stocate sunt
depuse pe server-ul Oracle, acceptă
parametri şi pot fi apelate prin nume.
copyright@www.adrian.runceanu.ro

2. Pachetele (stocate sau aplicaţie)


sunt blocuri neanonime care grupează:

1. proceduri
2. funcţii
3. cursoare
4. tipuri
5. constante
6. variabile - într-o unitate logică, în baza
de date
copyright@www.adrian.runceanu.ro

3. Declanşatorii sunt blocuri PL/SQL


neanonime depuse în baza de date, care pot
fi asociaţi bazei, iar în acest caz sunt
executaţi implicit ori de câte ori apare un
anumit eveniment declanşator:
copyright@www.adrian.runceanu.ro
 De exemplu, instrucţiuni INSERT, UPDATE
sau DELETE ce se execută asupra unui tabel
al bazei de date
 sau pot fi asociaţi unei aplicaţii (de exemplu,
declanşator SQL*Forms), ceea ce presupune
că se execută automat, în funcţie de anumite
condiţii sistem.
copyright@www.adrian.runceanu.ro

Structura unui bloc PL/SQL


Un bloc PL/SQL este compus din trei
secţiuni distincte:
1. Secţiunea declarativă (opţională) conţine
declaraţii pentru toate variabilele, constantele,
cursoarele şi erorile definite de utilizator la care
se face referinţă în secţiunea executabilă sau
chiar în cea declarativă.
 De asemenea, pot fi declarate subprograme
locale care sunt vizibile doar în blocul
respectiv.
2. Secţiunea executabilă conţine
copyright@www.adrian.runceanu.ro

instrucţiuni neprocedurale SQL pentru


prelucrarea datelor din baza de date şi
instrucţiuni PL/SQL pentru prelucrarea
datelor în cadrul blocului.
3. Secţiunea pentru tratarea erorilor
(opţională) specifică acţiunile ce vor fi
efectuate atunci când în execuţia
blocului apar erori sau condiţii
anormale.
copyright@www.adrian.runceanu.ro

Structura unui bloc PL/SQL


Blocul PL/SQL are următoarea structură
generală:
[<<nume_bloc>>]
[DECLARE
instrucţiuni de declarare]
BEGIN
instrucţiuni executabile (SQL sau PL/SQL)
[EXCEPTION
tratarea erorilor]
END [nume_bloc];
copyright@www.adrian.runceanu.ro

Dacă blocul PL/SQL este executat


fără erori, invariant va apărea mesajul:

PL/SQL procedure successfully


completed
copyright@www.adrian.runceanu.ro

Compatibilitate cu SQL
Din punct de vedere al compatibilităţii dintre
PL/SQL şi SQL, se remarcă următoarele reguli
de bază:
 PL/SQL furnizează:
◦ toate comenzile LMD (limbajul de manipulare
a datelor) ale lui SQL
◦ comanda SELECT cu clauza INTO
◦ comenzile LCD (limbajul de control al datelor)
◦ funcţiile
◦ pseudocoloanele
◦ şi operatorii SQL
 PL/SQL nu furnizează comenzile LDD (limbajul
de definire a datelor).
copyright@www.adrian.runceanu.ro

 Majoritatea funcţiilor SQL sunt


disponibile în PL/SQL.
 Există însă funcţii specifice PL/SQL,
cum sunt funcţiile SQLCODE şi
SQLERRM.
 De asemenea, există funcţii SQL care
nu sunt disponibile în instrucţiuni
procedurale (DECODE, funcţiile grup),
dar care sunt disponibile în
instrucţiunile SQL dintr-un bloc PL/SQL.
 SQL nu poate folosi funcţii sau atribute
specifice PL/SQL.
copyright@www.adrian.runceanu.ro

 Funcţiile de grup trebuie folosite cu


atenţie, deoarece clauza GROUP BY nu
are sens să apară în instrucţiunea
SELECT … INTO.

 Oracle9i introduce clauza OVER, care


permite ca funcţia grup căreia îi este
asociată să fie considerată o funcţie
analitică (poate returna mai multe linii
pentru fiecare grup).
copyright@www.adrian.runceanu.ro
Următoarele funcţii SQL nu sunt permise
în PL/SQL:
1. WIDTH_BUCKET
2. BIN_TO_NUM
3. COMPOSE
4. DECOMPOSE
5. TO_LOB
6. DECODE
7. DUMP
8. EXISTSNODE
9. TREAT
10. NULLIF
11. SYS_CONNECT_BY_PATH
12. SYS_DBURIGEN
13. EXTRACT
copyright@www.adrian.runceanu.ro

Întrebări?
Tehnici de programare cu baze de
date

#2 PL/SQL
Variabile şi tipuri de date

Adrian Runceanu
www.runceanu.ro/adrian
2022
copyright@www.adrian.runceanu.ro

Curs 2

Variabile şi tipuri de date


în PL/SQL
copyright@www.adrian.runceanu.ro

Cuprins

1. Mediul de programare PL/SQL:


ORACLE APPLICATION EXPRESS
2. Folosirea variabilelor în PL/SQL
3. Unităţile lexicale PL/SQL
4. Tipuri de date PL/SQL
5. Utilizarea tipurilor de date scalare
copyright@www.adrian.runceanu.ro

Oracle APEX 22.1.3 este o aplicatie web


bazata pe un browser ce ofera componentele
mediului de lucru SQL si PL/SQL
copyright@www.adrian.runceanu.ro

Oracle APEX 22.1.3 este o aplicatie web


bazata pe un browser ce ofera componentele
mediului de lucru SQL si PL/SQL
copyright@www.adrian.runceanu.ro

Cand va logati la Oracle Application Express si


selectati SQL Workshop puteti alege sa folositi:
1. Optiunea SQL Commands – pentru a folosi editorul
de comenzi SQL
2. Optiunea SQL Script – pentru a lucra cu editorul de
scripturi
copyright@www.adrian.runceanu.ro

Informatii utile despre APEX:

1. Oracle APEX Tutorial for Beginners (APEX 5.0):


http://o7planning.org/en/10345/oracle-apex-tutorial-for-
beginners

2.http://www.oracle.com/webfolder/technetwork/tutorials/
obe/db/devdays2012/apexp1_lab/apexp1_lab.html

Oracle APEX Release 22.1


3.https://docs.oracle.com/en/database/oracle/apex/22.1/
copyright@www.adrian.runceanu.ro

 Se poate folosi SQL Commands pentru a


introduce si executa o singura instructiune
SQL sau un singur bloc PL/SQL.

 Un script SQL poate contine una sau mai


multe instructiuni SQL, unul sau mai multe
blocuri PL/SQL.

 In aceasta situatie se foloseste SQL Scripts.


copyright@www.adrian.runceanu.ro
copyright@www.adrian.runceanu.ro
copyright@www.adrian.runceanu.ro

Instructiunea
DBMS_OUTPUT.PUT_LINE
 Instructiunea DBMS_OUTPUT.PUT_LINE
este foarte utilizata deoarece ne permite sa
afisam rezultatele pentru a verifica daca
blocurile ruleaza corect.

 Putem afisa:
1. un sir de caractere la un moment dat
2. concatena mai multe siruri de caractere intr-
unul singur
copyright@www.adrian.runceanu.ro

Instructiunea
DBMS_OUTPUT.PUT_LINE
Exemplu:

DECLARE
v_emp_count NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('PL/SQL is easy
so far!');
SELECT COUNT(*) INTO v_emp_count
FROM emp;
DBMS_OUTPUT.PUT_LINE(‘There are
'||v_emp_count||' rows in the employees table’);
END;
copyright@www.adrian.runceanu.ro

Instructiunea
DBMS_OUTPUT.PUT_LINE
copyright@www.adrian.runceanu.ro

Sintaxa unui bloc PL/SQL

 Un bloc anonim
PL/SQL se compune
din sectiuni si are
sintaxa următoare:

 Dacă blocul contine


o procedură
memorată în baza de
date, sintaxa sa este
următoarea:
copyright@www.adrian.runceanu.ro

Cuprins

1. Mediul de programare PL/SQL:


ORACLE APPLICATION EXPRESS
2. Folosirea variabilelor în PL/SQL
3. Unităţile lexicale PL/SQL
4. Tipuri de date PL/SQL
5. Utilizarea tipurilor de date scalare
copyright@www.adrian.runceanu.ro

2. Folosirea variabilelor in PL/SQL

 Vom studia declararea si initializarea


variabilelor in sectiunea declarativa a
unui bloc PL/SQL

 In PL/SQL se pot declara variabile care


apoi pot fi folosite in instructiunile SQL
si in cele procedurale.
copyright@www.adrian.runceanu.ro

2. Folosirea variabilelor in PL/SQL

Variabilele se utilizeaza pentru:

1. Stocarea temporara a datelor

2. Manipularea valorilor retinute

3. Refolosire
copyright@www.adrian.runceanu.ro

Manipularea variabilelor in PL/SQL

Variabilele sunt:
 Declarate si initializate in partea declarativa
 Folosite, si li se atribuite valori in partea
executabila

Variabilele pot fi:


 Transmise ca parametri subprogramelor
PL/SQL
 Folosite pentru a retine rezultatele unui
subprogram PL/SQL
copyright@www.adrian.runceanu.ro

Declararea variabilelor

 Toate variabilele PL/SQL trebuie declarate in


partea declarativa inainte de a fi referite de
catre blocul PL/SQL

 Scopul unei unei declarari este de a aloca


spatiu de memorie pentru o valoare,
specificarea tipului de date si denumirea
zonei de memorie pentru a putea fi folosita.

 Variabilele se pot declara in partea


declarativa a oricarui bloc, subprogram si
pachet PL/SQL
copyright@www.adrian.runceanu.ro

Declararea variabilelor – sintaxa

Identificator [ CONSTANT ] tip de date


[NOT NULL] [ :=expresie | DEFAULT
expresie ];
copyright@www.adrian.runceanu.ro

Initializarea variabilelor

 Variabilelor li se asociaza o locatie de


memorie in sectiunea DECLARE.
 Variabilelor li se atribuie o valoare la un
moment dat.
 Acest lucru se numeste initializare.
DECLARE
suma INTEGER := 0;
BEGIN
suma := suma + 1;
DBMS_OUTPUT.PUT_LINE(suma);
END;
copyright@www.adrian.runceanu.ro

Initializarea variabilelor
copyright@www.adrian.runceanu.ro

Exemple de declarare si
initializare a
variabilelor
-- Declaratii de variabile
nume VARCHAR2(30);
prenume VARCHAR2(25);
marca NUMBER(6);
activ BOOLEAN;
salariu_lunar NUMBER(6);
nr_zile_lucrate NUMBER(2);
salariu_zilnic NUMBER(6,2);
medie_zile_lucr CONSTANT NUMBER(2) := 21;
-- o constanta
BEGIN
NULL; -- NULL indica lipsa corpului. Este
permisa pt. testare.
END
copyright@www.adrian.runceanu.ro

Exemple de declarare
si initializare a
variabilelor
DECLARE
a integer := 10;
b integer := 20;
c integer;
f real;
BEGIN
c := a + b;
dbms_output.put_line('Valoarea
lui c: ' || c);
f := 70.0/3.0;
dbms_output.put_line('Valoarea
lui f: ' || f);
END;
copyright@www.adrian.runceanu.ro

Atribuirea de valori in sectiunea executabila

 Dupa ce o variabila a fost declarata o putem


folosi in sectiunea executabila a unui bloc
PL/SQL.

 De exemplu, in urmatorul bloc variabila


v_nume este declarata in sectiunea
DECLARE.

 Putem accesa aceasta variabila in sectiunea


executabila a aceluiasi bloc.
copyright@www.adrian.runceanu.ro

Ce credeti ca va afisa urmatorul bloc?

DECLARE
v_nume VARCHAR2(20);

BEGIN
DBMS_OUTPUT.PUT_LINE('Numele este
: '||v_nume);
v_nume := 'Ion';
DBMS_OUTPUT.PUT_LINE('Numele este
: '||v_nume);
END;
copyright@www.adrian.runceanu.ro

 In acest exemplu, valoarea Ion este


atribuita unei variabile in sectiunea
executabila.

 Valoarea variabilei este concatenata cu


sirul de caractere Numele este:

 Rezultatul afisat este:


Numele este :
Numele este : Ion
Statement processed.
copyright@www.adrian.runceanu.ro
 In urmatorul bloc variabila v_nume este
declarata si initializata in sectiunea
declarativa.
 v_nume stocheaza valoarea Ion dupa
initializare.
Valoarea este folosita in sectiunea
executabila a blocului.
DECLARE
v_nume VARCHAR2(20):= 'Ion';
BEGIN
v_nume := 'Stefan';
DBMS_OUTPUT.PUT_LINE('Numele este :
'||v_nume);
END;
Se va afisa: Numele este : Stefan
copyright@www.adrian.runceanu.ro

Transmiterea variabilelor ca parametri in


subprogramele PL/SQL

 Parametrii sunt valori transmise


programului de catre utilizator sau de catre
alt program pentru personalizarea
programului.

 In PL/SQL subprogramele pot prelua


parametri.

 Se pot transmite variabilele ca parametri ai


procedurilor si functiilor.
copyright@www.adrian.runceanu.ro

 In urmatorul exemplu parametrul v_date este


transmis procedurii PUT_LINE care face
parte din pachetul DBMS_OUTPUT.
DECLARE Afiseaza data
calendaristica
v_date VARCHAR2(30); curenta
BEGIN
SELECT TO_CHAR(SYSDATE) INTO v_date
FROM dual;
DBMS_OUTPUT.PUT_LINE(v_date);
END;
copyright@www.adrian.runceanu.ro

Cuprins

1. Mediul de programare PL/SQL:


ORACLE APPLICATION EXPRESS
2. Folosirea variabilelor în PL/SQL
3. Unităţile lexicale PL/SQL
4. Tipuri de date PL/SQL
5. Utilizarea tipurilor de date scalare
copyright@www.adrian.runceanu.ro

3. UNITATILE LEXICALE PL/SQL


Unitati lexicale intr-un bloc PL/SQL:
1. Blocurile
2. Siruri de caractere ce includ:
◦ litere
◦ cifre
◦ tab-uri si alte simboluri
Unitatile lexicale pot fi clasificate in:
3.1. Identificatori
3.2. Cuvinte rezervate
3.3. Delimitatori
3.4. Literali
3.5. Comentarii
copyright@www.adrian.runceanu.ro

3.1. Identificatorii

 Un identificator este un nume dat unui


obiect PL/SQL, incluzand pe oricare dintre
urmatoarele:

Procedure Function Variable

Exception Constant Package

Record PL/SQL table Cursor


copyright@www.adrian.runceanu.ro

3.1. Identificatorii
Proprietatile unui identificator:

1. contine cel mult 30 de caractere

2. trebuie sa inceapa cu o litera

3. poate contine caracterele $, _ (underscore), #

4. nu poate contine spatii

5. identificatorii nu sunt case sensitive


copyright@www.adrian.runceanu.ro

3.1. Identificatorii
Exemple de identificatori corecti
First_Name LastName address_1
ID# Total_$ primary_department_contact

Exemple de identificatori incorecti


First Name Contains a space
Last-Name Contains invalid "-"
1st_address_line Begins with a number
Total_% Contains invalid "%"
primary_building_department_contact More than 30 characters
copyright@www.adrian.runceanu.ro

3.2. Cuvinte rezervate


 Cuvintele rezervate sunt acele cuvinte care au o
semnificatie speciala pentru baza de date Oracle.
 Cuvintele rezervate nu pot fi folosite ca identificatori
intr-un program PL/SQL.
 O parte dintre cuvintele rezervate sunt:

ALL CREATE FROM MODIFY SELECT


ALTER DATE GROUP NOT SYNONYM
AND DEFAULT HAVING NULL SYSDATE
ANY DELETE IN NUMBER TABLE
AS DESC INDEX OR THEN
ASC DISTINCT INSERT ORDER UPDATE
BETWEEN DROP INTEGER RENAME VALUES
CHAR ELSE INTO ROW VARCHAR2
COLUMN EXISTS IS ROWID VIEW
COMMENT FOR LIKE ROWNUM WHERE
copyright@www.adrian.runceanu.ro

3.3. Delimitatori
 Delimitatorii sunt simboluri care au
semnificatie speciala pentru baza de date
Oracle:
 Delimitatori simpli:

Symbol Meaning
+ Addition operator
– Subtraction/negation operator
* Multiplication operator
/ Division operator
= Equality operator
' Character string delimiter
; Statement terminator
copyright@www.adrian.runceanu.ro

Delimitatorii compusi:

Symbol Meaning
<> Inequality operator
!= Inequality operator
|| Concatenation operator
-- Single-line comment indicator
/* Beginning comment delimiter
*/ Ending comment delimiter
:= Assignment operator
copyright@www.adrian.runceanu.ro

3.4. Literali:

 Un literal poate fi un numar, un sir de


caractere, o data calendaristica sau o
valoare booleana explicita care nu poate
fi reprezentata printr-un identificator.

Literalii se clasifica:
3.4.1. literali de tip sir de caractere
3.4.2. literali de tip numeric
3.4.3. literali de tip Boolean
copyright@www.adrian.runceanu.ro

3.4.1. Literalii siruri de caractere

 Literalii siruri de caractere includ toate


caracterele printabile din multimea de
caractere PL/SQL:
◦ litere
◦ numere
◦ spatii
◦ simboluri speciale

 Literalii siruri de caractere sunt de tipul


CHAR si trebuie scrisi intre apostrofuri
copyright@www.adrian.runceanu.ro

3.4.1. Literalii siruri de caractere

 Literalii siruri de caractere pot fi formati din


0 sau mai multe caractere din multimea de
caractere PL/SQL
 Literalii siruri de caractere sunt case
sensitive
Exemple:

v_prenume := 'Ion';
v_grupa := '134A';
v_data_astazi := '13-OCT-2015';
copyright@www.adrian.runceanu.ro

3.4.2. Literalii de tip numeric

 Literalii numerici sunt valori numerice intregi


sau reale
 Literalii numerici se pot reprezenta ca o
valoare simpla (de exemplu -32.5) sau prin
notatia stiintifica (de exemplu 2E5 ce
semnifica 2*105 -> 200000)
Exemple:
v_elevation := 428;
v_order_subtotal := 1025.69;
v_growth_rate := .56;
v_distance_sun_to_centauri := 4.3E13;
copyright@www.adrian.runceanu.ro

3.4.3. Literalii de tip Boolean


 Literalii de tip Boolean sunt valori ce sunt
atribuite variabilelor booleene
 Literalii de tip Boolean nu se pun intre
apostrofuri sau ghilimele
 TRUE, FALSE si NULL sunt literali de tip
Boolean sau cuvinte cheie
Exemple:
v_new_customer := FALSE;
v_paid_in_full := TRUE;
v_authorization_approved := FALSE;
v_high_school_diploma := NULL;
v_island :=FALSE;
copyright@www.adrian.runceanu.ro

3.5. Comentarii

 Comentariile ofera explicatii cu privire la


ceea ce realizeaza un anumit cod de
program.
 Comentariile plasate acolo unde trebuie sunt
foarte importante pentru intelegerea si
intretinerea viitoare a programului.
 Folosirea comentariilor este o buna practica
in programare.
 Comentariile sunt ignorate de PL/SQL. Sunt
instructiuni pe care PL/SQL nu le executa.
copyright@www.adrian.runceanu.ro

3.5. Comentarii
copyright@www.adrian.runceanu.ro

Cuprins

1. Mediul de programare PL/SQL:


ORACLE APPLICATION EXPRESS
2. Folosirea variabilelor în PL/SQL
3. Unităţile lexicale PL/SQL
4. Tipuri de date PL/SQL
5. Utilizarea tipurilor de date scalare
copyright@www.adrian.runceanu.ro

4. Tipuri de date PL/SQL

 Un tip de date specifica un format de


stocare, restrictii si un domeniu de valori.

 PL/SQL suporta 5 categorii de tipuri de date:

1. Scalar – stocheaza o singura valoare

2. Compus – contine elemente care pot fi


atat de tip scalar (record) cat si de tip
compus (record si tabela)
copyright@www.adrian.runceanu.ro

4. Tipuri de date PL/SQL


3. LOB (Large Object) – stocheaza valori ce
sunt denumite locatori care specifica locatia
unor obiecte mari (cum ar fi imaginile grafice)
care sunt stocate out of line.

4. Referinta – stocheaza valori, se numesc


pointeri si indica catre o locatie de memorie

5. Obiect – Este un obiect schema care are


nume, atribute si metode. Un tip de date obiect
este asemanator ca mecanism cu clasele din
C++ si Java
copyright@www.adrian.runceanu.ro

4.1. Tipurile de date scalare

 Stocheaza o singura valoare

 Nu au componente interne

 Pot fi clasificate in 4 categorii:


1. Character
2. Number
3. Date
4. Boolean
copyright@www.adrian.runceanu.ro

 Tipuri de date scalare:


Character (or String)
Base type for fixed-length character
data up to 32,767 bytes. If you do
CHAR [(maximum_length)]
not specify a maximum_length, the
default length is set to 1.
Base type for variable-length character
data up to 32,767 bytes. There is no
VARCHAR2(maximum_length)
default size for VARCHAR2
variables and constants.
Character data of variable length (a
LONG bigger version of the VARCHAR2
data type).
Raw binary data of variable length (not
LONG RAW
interpreted by PL/SQL).
copyright@www.adrian.runceanu.ro

 Tipuri de date scalare: Number

Number having precision p and scale s. The


NUMBER
precision p can range from 1 to 38.
[(precision, scale)]
The scale s can range from –84 to 127.
Base type for signed integers between
BINARY_INTEGER
-2,147,483,647 and 2,147,483,647.
Base type for signed integers between
-2,147,483,647 and 2,147,483,647.
PLS_INTEGER PLS_INTEGER and BINARY_INTEGER values
require less storage and are faster than
NUMBER values.
New data types introduced in Oracle Database
10g.
BINARY_FLOAT They represent a floating-point number in the
BINARY_DOUBLE IEEE 754 format.
BINARY_FLOAT requires 5 bytes to store the
value and BINARY_DOUBLE requires 9 bytes.
copyright@www.adrian.runceanu.ro
 Tipuri de date scalare: Date
Base type for dates and times. DATE values include the time of day
DATE in seconds since midnight.
The range for dates is between 4712 B.C. and A.D. 9999.
The TIMESTAMP data type, which extends the DATE data type,
TIMESTAMP stores the year, month, day, hour, minute, second, and fraction
of seconds.
The TIMESTAMP WITH TIME ZONE data type, which extends the
TIMESTAMP data type, includes a time-zone displacement—
TIMESTAMP WITH TIME
that is, the difference (in hours and minutes) between local time
ZONE and Coordinated Universal Time (UTC), formerly known as
Greenwich Mean Time.

This data type differs from TIMESTAMP WITH TIME ZONE in that
when you insert a value into a database column, the value is
TIMESTAMP WITH LOCAL normalized to the database time zone, and the time-zone
TIME ZONE displacement is not stored in the column.
When you retrieve the value, the Oracle server returns the value in
your local session time zone.
INTERVAL YEAR TO You use the INTERVAL YEAR TO MONTH data type to store and
MONTH manipulate intervals of years and months.

INTERVAL DAY TO You use the INTERVAL DAY TO SECOND data type to store and
SECOND manipulate intervals of days, hours, minutes, and seconds
copyright@www.adrian.runceanu.ro

 Tipuri de date scalare: Boolean

Base type that stores one of the three possible values


BOOLEAN
used for logical calculations: TRUE, FALSE, or NULL.
copyright@www.adrian.runceanu.ro

Tipuri de date compuse:

 Un tip de date scalar nu are componente


interne.

 Un tip compus are componente interne care


pot fi folosite individual.

 Tipurile de date compuse includ urmatoarele:


1. TABLE
2. RECORD
3. NESTED TABLE
4. VARRAY
copyright@www.adrian.runceanu.ro

3. Tipul de date LOB

 Obiectele de mari dimensiuni (Lobs) au rolul


de a stoca un volum mare de informatii

 O coloana dintr-o baza de date se poate


incadra in categoria LOB

 Tipurile de date LOB permit un acces eficient


si aleator la date, si pot fi atributele unui tip
obiect
copyright@www.adrian.runceanu.ro

3. Tipul de date LOB

 Exista cateva categorii de tipuri de date LOB:


1. Character large object (CLOB)
2. Binary large object (BLOB)
3. Binary file (BFILE)
4. National language character large object
(NCLOB)

 Tipurile de date LOB ne permit sa stocam


blocuri de date nestructurate de o dimensiune
pana la 4 gigabytes
copyright@www.adrian.runceanu.ro

 Book (CLOB)

 Photo(BLOB)

 Movie (BFILE)

 NCLOB
copyright@www.adrian.runceanu.ro

Cuprins

1. Mediul de programare PL/SQL:


ORACLE APPLICATION EXPRESS
2. Folosirea variabilelor în PL/SQL
3. Unităţile lexicale PL/SQL
4. Tipuri de date PL/SQL
5. Utilizarea tipurilor de date scalare
copyright@www.adrian.runceanu.ro

5. Utilizarea tipurilor de date scalare

Declararea variabilelor de tip character:

 Tipurile de date CHARACTER includ: CHAR,


VARCHAR2 si LONG

DECLARE
v_emp_job VARCHAR2(9);
v_order_no VARCHAR2(6);
v_product_id VARCHAR2(10);
v_rpt_body_part LONG;
copyright@www.adrian.runceanu.ro

Declararea variabilelor numerice

 Tipurile de date numerice includ: NUMBER,


PLS_INTEGER, BINARY_INTEGER si
BINARY_FLOAT.
 Daca se foloseste constrangerea CONSTANT,
valoarea variabilei nu se poate schimba.
 Constantele trebuie initializate.
INTEGER este un alias pentru NUMBER(38,0).
DECLARE
v_dept_total_sal NUMBER(9,2) := 0;
v_count_loop INTEGER := 0;
c_tax_rate CONSTANT NUMBER(3,2) := 8.25;
copyright@www.adrian.runceanu.ro

Declararea variabilelor de tip date (data


calendaristica)

 Tipurile DATE includ:


1. DATE
2. TIMESTAMP
3. TIMESTAMP WITH TIMEZONE

DECLARE
v_orderdate DATE := SYSDATE + 7;
v_natl_holiday DATE;
v_web_sign_on_date TIMESTAMP;
copyright@www.adrian.runceanu.ro

Declararea variabilelor booleene

 Tipul de date BOOLEAN stocheaza 3 valori


folosite pentru expresii logice:
1. TRUE
2. FALSE
3. NULL

DECLARE
v_valid BOOLEAN NOT NULL := TRUE;
v_is_found BOOLEAN := FALSE;
v_underage BOOLEAN;
copyright@www.adrian.runceanu.ro

Declararea variabilelor booleene(continuare)

 Unei variabile de tip boolean i se poate atribui


doar una dintre valorile: TRUE, FALSE,
NULL

 Expresiile conditionale folosesc operatorii


logici AND, OR si NOT pentru a verifica
valorile variabilelor

 Pentru a returna valori de tip Boolean, se pot


folosi expresii aritmetice, de tip char sau data
calendaristica.
copyright@www.adrian.runceanu.ro

Reguli pentru declararea si initializarea


variabilelor PL/SQL

 Folositi nume semnificative si respectati


conventiile de denumire

 Declarati un singur identificator pe linie pentru


o vizualizare mai buna, pentru o intelegere si
intretinere a codului mai usoara

 Folositi restrictia NOT NULL atunci cand doriti


ca variabila sa contina o valoare

 Evitati folosirea denumirilor de coloane ca


identificatori
copyright@www.adrian.runceanu.ro

Exemplu de utilizare incorecta a denumirilor de variabile:


DECLARE
empno NUMBER(4,0); Numele variabilei
BEGIN este identic cu
SELECT empno numele coloanei
INTO empno
FROM emp
WHERE deptno = 10;
END;
copyright@www.adrian.runceanu.ro

Variabilele de ancorare cu atributul %TYPE

 Uneori, decat sa apelati la un cod care s-ar


scrie mai dificil, este indicat sa folositi atributul
%TYPE pentru a declara o variabila in acelasi
fel cu o alta variabila declarata anterior sau cu
o coloana a bazei de date.
 Atributul %TYPE este folosit mai ales atunci
cand valoarea stocata in variabila este
derivata dintr-o tabela a bazei de date.
 Cand folosim atributul %TYPE pentru a
declara o variabila, il vom prefixa cu
denumirea tabelei din baza de date si a
coloanei.
copyright@www.adrian.runceanu.ro

Exemplu de tabela si de bloc PL/SQL care o


foloseste:

CREATE TABLE myemps (


emp_name VARCHAR2(6),
emp_salary NUMBER(6,2));
DECLARE
v_emp_salary NUMBER(6,2);
BEGIN
SELECT emp_salary
INTO v_emp_salary
FROM myemps
WHERE emp_name = 'Smith';
END;
copyright@www.adrian.runceanu.ro

 Acest bloc PL/SQL stocheaza salariul corect


in variabila v_emp_salary.
 Dar ce se va intampla daca coloana tabelei va
fi modificata ulterior?
 Atributul %TYPE:
◦ Este folosit pentru a da automat unei
variabile acelasi tip de date si aceeasi
dimensiune ca si:
 In definirea unei coloane dintr-o tabela
 O variabila declarata anterior
◦ Este prefixat cu oricare dintre urmatoarele:
 Denumirea unei tabele dintr-o baza de date si a
unei coloane
 Numele unei alte variabile declarate anterior
copyright@www.adrian.runceanu.ro

Declararea variabilelor cu atributul %TYPE

Sintaxa:
identifier table.column_name%TYPE;

Exemple
...
v_emp_lname
employees.last_name%TYPE;
v_balance NUMBER(7,2);
v_min_balance v_balance%TYPE := 1000;
...
copyright@www.adrian.runceanu.ro

Avantajele atributului %TYPE

 Se pot evita erorile cauzate de nepotrivirile de


tip de date sau de precizie

 Nu este necesara schimbarea declaratiei


variabilei daca se schimba definirea coloanei

 Atunci cand se foloseste atributul %TYPE,


PL/SQL determina tipul de date si
dimensiunea variabilei la compilarea blocului.
Acest lucru asigura compatibilitatea variabilei
cu coloana pe care o va complete.
copyright@www.adrian.runceanu.ro
Exemplu
CREATE TABLE myemps (
emp_name VARCHAR2(6),
emp_salary NUMBER(6,2));
DECLARE
v_emp_salary myemps.emp_salary%TYPE;
BEGIN
SELECT emp_salary
INTO v_emp_salary
FROM myemps
WHERE emp_name = 'Smith';
END;
 Blocul PL/SQL continua sa ruleze corect chiar daca
tipul de date al coloanei este modificat ulterior
copyright@www.adrian.runceanu.ro

Întrebări?
Tehnici de programare cu baze de
date

#3 PL/SQL
Funcţii SQL, operatori şi
vizibilitatea variabilelor

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 3

Funcţii SQL, operatori şi


vizibilitatea variabilelor în
PL/SQL

2
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor
in blocurile imbricate
3
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL

Sunt deja cunoscute instructiunile SQL.


De exemplu:
SELECT *
FROM EMP;

4
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Exista functii SQL care pot fi folosite si in
instructiunile procedurale PL/SQL.

De exemplu:
DECLARE
v_last_day DATE;
BEGIN
v_last_day := LAST_DAY(SYSDATE);
DBMS_OUTPUT.PUT_LINE(v_last_day);
END;

5
copyright@www.adrian.runceanu.ro

6
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Sunt disponibile in instructiunile procedurale:
1. Functiile single-row pentru caractere
2. Functiile numerice single-row
3. Functiile pentru date calendaristice
4. Functiile pentru conversiile de tipuri de date
5. Functii diverse

Nu sunt disponibile in instructiunile


procedurale:
1. DECODE
2. Functiile de grup (functiile multiple-row)

7
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


1. Functii pentru caractere:

Functiile pentru caractere valide in PL/SQL


sunt:

ASCII LENGTH RPAD


CHR LOWER RTRIM
CONCAT LPAD SUBSTR
INITCAP LTRIM TRIM
INSTR REPLACE UPPER
8
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Exemple de functii pentru caractere:

Referitor la lungimea unui sir

v_desc_size INTEGER(5);
v_prod_description VARCHAR2(70):='You
can use this product with your radios for
higher frequency';

v_desc_size:= LENGTH(v_prod_description);

9
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Scrierea numelui capitalei unei tari cu
majuscule:

v_capitol_name:= UPPER(v_capitol_name);

Concatenarea prenumelui cu numele:

v_emp_name:=v_first_name||'
'||v_last_name;

10
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


2. Functii numerice

Functiile numerice valide in PL/SQL includ:

ABS EXP ROUND


ACOS LN SIGN
ASIN LOG SIN
ATAN MOD TAN
COS POWER TRUNC

11
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Exemple de functii numerice

Preluarea semnului unui numar

DECLARE
v_my_num BINARY_INTEGER :=-56664;

BEGIN
DBMS_OUTPUT.PUT_LINE(SIGN(v_my
_num));
END;
12
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Rotunjirea unei valori numerice
DECLARE
v_median_age NUMBER(6,2);
BEGIN
SELECT median_age
INTO v_median_age
FROM countries
WHERE country_id=27;
DBMS_OUTPUT.PUT_LINE(ROUND(v_median
_age,0));
END;
13
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


3. Functii pentru date calendaristice

Functiile pentru date calendaristice valide in


PL/SQL includ:
ADD_MONTHS MONTHS_BETWEEN
CURRENT_DATE ROUND
CURRENT_TIMESTAMP SYSDATE
LAST_DAY TRUNC

14
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Exemple de functii pentru date calendaristice:
Adunarea unui anumit numar de luni la o data
calendaristica
DECLARE
v_new_date DATE;
v_num_months NUMBER := 6;
BEGIN
v_new_date := ADD_MONTHS(SYSDATE,
v_num_months);
DBMS_OUTPUT.PUT_LINE(v_new_date);
END;
15
copyright@www.adrian.runceanu.ro

16
copyright@www.adrian.runceanu.ro

1. Functiile SQL in PL/SQL


Calcularea numarului de luni dintre doua date
calendaristice
DECLARE v_no_months PLS_INTEGER:=0;
BEGIN
v_no_months := months_between (to_date
('2021/06/01', 'yyyy/mm/dd'), to_date
('2021/03/14', 'yyyy/mm/dd') );
DBMS_OUTPUT.PUT_LINE(v_no_months);
END;Rezultat:
3
Statement processed.
0.01 seconds
17
copyright@www.adrian.runceanu.ro

18
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor in
blocurile imbricate

19
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date


 In orice limbaj de programare conversia de la
un tip de date la altul este o cerinta obisnuita.

 PL/SQL poate manipula astfel de conversii cu


tipuri de date scalare.

Conversiile de tipuri de date pot fi de doua


tipuri:
1. Conversii implicite
2. Conversii explicite

20
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date

1. Conversii implicite

 In conversiile implicite, PL/SQL incearca


convertirea tipurilor de date dinamic, daca
sunt in diverse forme, intr-o instructiune.

 Conversiile implicite pot avea loc intre multe


tipuri de date in PL/SQL dupa cum sunt
ilustrate in urmatoarea schema:

21
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date

DATE LONG NUMBER PLS_INTEGER VARCHAR2

DATE N/A X X

LONG N/A X

NUMBER X N/A X X

PLS_INTEGER X X N/A X

VARCHAR2 X X X X N/A

22
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date


Exemple de conversie implicita
DECLARE
v_salary NUMBER(6):=6000;
v_sal_increase VARCHAR2(5):='1000';
v_total_salary v_salary%TYPE;
BEGIN
v_total_salary:= v_salary + v_sal_increase;
DBMS_OUTPUT.PUT_LINE(v_total_salary);
END;
 In acest exemplu, variabila v_sal_increase este de
tipul VARCHAR2.
 Atunci cand este calculat salariul total, PL/SQL mai
intai converteste v_sal_increase in numar, iar apoi
efectueaza calculele.
 Rezultatul expresiei este de tip numeric. 23
copyright@www.adrian.runceanu.ro

Dezavantajele conversiilor implicite

 La prima vedere, conversiile implicite par a fi


utile.
 Totusi exista cateva dezavantaje:
1. Conversiile implicite pot fi mai lente

2. Cand se folosesc conversiile implicite


pierdem controlul asupra programului
deoarece nu stim exact cum manipuleaza
Oracle datele. Daca Oracle schimba regulile
de conversie atunci va fi afectat codul
programului.
24
copyright@www.adrian.runceanu.ro

Dezavantajele conversiilor implicite

3. Regulile de conversie implicita depind de


mediul de programare.
 De exemplu, formatul datelor calendaristice
depinde de setarile de limbaj si de tipul
instalarii.
 Codurile care folosesc conversii implicite pot
sa nu ruleze pe alte servere sau in alte
limbaje.

4. Codurile care folosesc conversiile implicite


sunt mai greu de citit si de inteles.
25
copyright@www.adrian.runceanu.ro

5. Este responsabilitatea programatorului sa se


asigure ca valorile pot fi convertite.
 De exemplu, PL/SQL poate converti valoarea CHAR ’13-OCT-15’
la o valoare de tip data calendaristica, dar nu poate converti
valoarea CHAR ‘Yesterday’ la data calendaristica.
 In mod asemanator, PL/SQL nu poate converti o valoare de tip
VARCHAR2 care contine caractere alfabetice la o valoare
numerica.

Valid? Statement

Yes v_new_date DATE := '13-OCT-2015';

No v_new_date DATE := 'Yesterday';

Yes v_my_number NUMBER := '123';

No v_my_number NUMBER := 'abc';


26
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date


2. Conversii explicite
Conversiile explicite convertesc valori de la
un tip de date la altul cu ajutorul functiilor
built-in.
Exemple de functii de conversie:

TO_NUMBER() ROWIDTONCHAR()
TO_CHAR() HEXTORAW()
TO_CLOB() RAWTOHEX()
CHARTOROWID() RAWTONHEX()
ROWIDTOCHAR() TO_DATE()
27
copyright@www.adrian.runceanu.ro

TO_CHAR
BEGIN
DBMS_OUTPUT.PUT_L
INE(TO_CHAR(SYSDA
TE, 'Month YYYY'));
END;

Rezultat:
October 2021

28
copyright@www.adrian.runceanu.ro

TO_DATE
BEGIN
DBMS_OUTPUT.PU
T_LINE(to_date('20
211018',
'yyyymmdd'));
END;

Rezultat:
10/18/2021

29
copyright@www.adrian.runceanu.ro

2. Conversii de tipuri de date


TO_NUMBER

DECLARE
v_a VARCHAR2(10) := '-123456';
v_b VARCHAR2(10) := '+987654';
v_c PLS_INTEGER;
BEGIN
v_c := TO_NUMBER(v_a) + TO_NUMBER(v_b);
DBMS_OUTPUT.PUT_LINE(v_c);
END;

Rezultat:
864198
30
copyright@www.adrian.runceanu.ro

31
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor in
blocurile imbricate

32
copyright@www.adrian.runceanu.ro

3. Operatori in PL/SQL
Operatori in PL/SQL:
1. Logici
2. Aritmetici
3. De concatenare
4. Parantezele care controleaza
ordinea operatiilor
5. Operatorul exponential (**)
Operatorii dintr-o expresie se
executa intr-o anumita ordine, in functie
de prioritatea lor.
33
copyright@www.adrian.runceanu.ro
Tabelul urmator prezinta ordinea implicita
a operatorilor de la prioritatea cea mai mare la
cea mai mica.

Operator Operatie
** Ridicare la putere
*, / Inmultire, impartire
Adunare, scadere,
+, -, ||
concatenare
=,<,>,<=,>=,<>,!=,~=,^=,
Comparatie
IS NULL,LIKE,BETWEEN,IN
NOT Negatie logica
AND Conjunctie
OR Disjunctie
34
copyright@www.adrian.runceanu.ro

3. Operatori in PL/SQL
Exemple
Incrementarea contorului dintr-o bucla
v_loop_count := v_loop_count + 1;
Setarea unei valori a unui flag boolean
v_good_salary := v_sal BETWEEN 50000
AND 150000;
Verificarea daca ID-ul unui angajat contine
o valoare
v_valid := (v_empno IS NOT NULL);

35
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor in
blocurile imbricate

36
copyright@www.adrian.runceanu.ro

4. Blocuri imbricate si vizibilitatea


variabilelor
 Un bloc mare, complex este greu de inteles.
 Îl putem imparti in blocuri mai mici care sunt
imbricate unele in altele, facand codul mai
usor de inteles si de corectat.
 Atunci cand imbricam blocuri, variabilele
declarate pot sa nu mai fie valabile, aceasta
depinzand de vizibilitatea lor si locul unde sunt
declarate.
 Puteti face ca variabilele invizibile sa devina
valabile prin utilizarea etichetelor.

37
copyright@www.adrian.runceanu.ro

4. Blocuri imbricate si vizibilitatea


variabilelor
Blocuri imbricate
 PL/SQL este un limbaj care are la baza
blocurile.
 Unitatile de baza (proceduri, functii si blocuri
anonime) sunt blocurile, care pot contine
oricate subblocuri imbricate.
 Fiecare bloc logic corespunde unei probleme
de rezolvat.
 Urmatorul exemplu are un bloc exterior
(parinte) si un bloc imbricat (copil).
 Variabila v_outer_variable este declarata in
blocul exterior si variabila v_inner_variable
este declarata in blocul interior. 38
copyright@www.adrian.runceanu.ro

4. Blocuri imbricate si vizibilitatea


variabilelor
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;
39
copyright@www.adrian.runceanu.ro

40
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor in
blocurile imbricate

41
copyright@www.adrian.runceanu.ro

5. Domeniul de aplicare al variabilelor

 Domeniul de aplicabilitate al unei variabile


este blocul sau blocurile in care variabila
este accesibila, poate fi numita si utilizata.

 In PL/SQL domeniul de vizibilitate a unei


variabile este blocul in care este declarata
si toate blocurile imbricate in blocul
declarativ.

42
copyright@www.adrian.runceanu.ro

5. Domeniul de aplicare al variabilelor


Care este domeniul de vizibilitate al fiecarei variabile?
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='APR-20-1972';

BEGIN
DECLARE v_child_name VARCHAR2(20):='Mike';
BEGIN
DBMS_OUTPUT.PUT_LINE('Father''s Name: '||v_father_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
DBMS_OUTPUT.PUT_LINE('Child''s Name: '||v_child_name);
END;
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
END;

43
copyright@www.adrian.runceanu.ro

44
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor
in blocurile imbricate
45
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


Variabilele declarate intr-un bloc PL/SQL
sunt considerate locale in acel bloc si globale
pentru toate subblocurile lui.
v_outer_variable este locala pentru blocul
exterior, dar globala pentru blocul interior.
Mod de functionare:
1. Cand accesam aceasta variabila in blocul
interior, PL/SQL cauta mai intai o variabila
locala in blocul interior cu acel nume.
2. Daca nu este nici o variabila cu acel nume,
PL/SQL cauta variabila in blocul exterior.
46
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


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;

47
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale

48
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


 Variabila v_inner_variable este locala
blocului interior si nu este globala deoarece
blocul interior nu are alte blocuri imbricate.

 Aceasta variabila poate fi accesata doar in


blocul interior.

 Daca PL/SQL nu gaseste variabila declarata


local atunci cauta in sus in partea declarativa
a blocului parinte.

 PL/SQL nu cauta in jos blocurile copii. 49


copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


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;
50
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale

51
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


Variabilele v_father_name si v_date_of_birth
sunt declarate in blocul exterior.
Sunt locale blocului exterior si globale celui
interior.
Domeniul lor de aplicare include ambele
blocuri.
DECLARE
v_date_of_birth DATE:='APR-20-1972';
v_father_name VARCHAR2(20):='Patrick';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
…. 52
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


 Variabila v_child_name este declarata in blocul
interior (cel imbricat).
 Aceasta variabila este accesibila doar in blocul
imbricat si nu este accesibila in blocul exterior.
a) Denumirea variabilelor
 Nu putem declara doua variabile cu acelasi
nume in acelasi bloc.
 Oricum, putem declara variabile cu acelasi nume
in doua blocuri diferite (blocuri imbricate).
 Cele doua elemente reprezentate prin acelasi
nume sunt distincte si orice modificare a unuia
nu afecteaza pe celalalt.
53
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


b) Vizibilitatea variabilelor
Ce se intampla daca acelasi nume este folosit pentru
doua variabile, cate una in fiecare bloc?
In exemplul urmator, variabila v_date_of_birth este
declarata de doua ori:
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='APR-20-1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-12-2002';
BEGIN
DBMS_OUTPUT.PUT_LINE('Date of Birth:'
||v_date_of_birth); 54
copyright@www.adrian.runceanu.ro
Care v_date_of_birth este referita de instructiunea
DBMS_OUTPUT.PUT_LINE?
Vizibilitatea unei variabile este portiunea de program unde variabila
poate fi accesata fara a folosi unui calificativ.
Care este vizibilitatea fiecarei variabile?
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='Apr-20-1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-12-2002';
BEGIN
DBMS_OUTPUT.PUT_LINE('Father''s Name:
'||v_father_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth:
'||v_date_of_birth);
DBMS_OUTPUT.PUT_LINE('Child''s Name:
'||v_child_name);
END;
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
55
END;
copyright@www.adrian.runceanu.ro
Care v_date_of_birth este referita de instructiunea
DBMS_OUTPUT.PUT_LINE?
Vizibilitatea unei variabile este portiunea de program unde variabila
poate fi accesata fara a folosi unui calificativ. Se afiseaza
Care este vizibilitatea fiecarei variabile? data de nastere
corecta?

Se afiseaza
data de nastere
corecta?

56
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


 Variabila v_date_of_birth declarata in blocul
exterior are domeniul de aplicabilitate si in
blocul interior.
 Aceasta variabila este vizibila in blocul
exterior.
 Oricum ea nu este vizibila in blocul interior
deoarece acesta are o variabila cu acelasi
nume.
 Variabila v_father_name este vizibila atat in
blocul interior cat si in cel exterior.
 Variabila v_child_name este vizibila doar in
blocul interior. 57
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='Apr-20-1972';

BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-12-2002';

58
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale


c) Calificarea unui identificator
Un calificator este o eticheta data unui bloc.
Putem folosi acest calificativ pentru a accesa variabilele
care au domeniu dar nu sunt vizibile.
In urmatorul exemplu blocul exterior are eticheta
<<outer>>.

<<outer>>
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='Apr-20-1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-12-2002'; 59
copyright@www.adrian.runceanu.ro

Etichetele nu se pun doar blocului exterior. Se pot pune oricarui


bloc.
Folosind eticheta outer pentru a califica identificatorul
v_date_of_birth, putem afisa acum data de nastere a tatalui in
blocul interior.
<<outer>>
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='Apr-12-1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-20-2002';
BEGIN
DBMS_OUTPUT.PUT_LINE('Father''s Name: '||v_father_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth: '
||outer.v_date_of_birth);
DBMS_OUTPUT.PUT_LINE('Child''s Name: '||v_child_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
END;
END;

60
copyright@www.adrian.runceanu.ro

6. Variabile locale si globale

Se vor afisa datele de


nastere corecte:

Father’s Name: Patrick


Date of Birth: 04/20/1972
Child’s Name: Mike
Date of Birth: 12/12/2002

Statement processed.

61
copyright@www.adrian.runceanu.ro

Cuprins

1. Functiile SQL in PL/SQL


2. Conversii de tipuri de date
3. Operatori in PL/SQL
4. Blocuri imbricate si vizibilitatea
variabilelor
5. Domeniul de aplicare al variabilelor
6. Variabile locale si globale
7. Domeniul de aplicare a exceptiilor
in blocurile imbricate
62
copyright@www.adrian.runceanu.ro

7. Domeniul de aplicare a
exceptiilor in blocurile imbricate

O exceptie este o sectiune de programare care


captureaza erorile pentru a opri brusc
programul.

Se poate administra o exceptie prin:

1. Manipularea ei („prinderea ei in cursa”) in


blocul in care apare

2. Propagarea ei in mediul apelant


63
copyright@www.adrian.runceanu.ro

7. Domeniul de aplicare a
exceptiilor in blocurile imbricate
1. Prinderea in cursa a exceptiilor cu un
handler
 Este bine sa includem o sectiune de exceptii
intr-un program PL/SQL.
 Daca exceptia apare in partea executabila a
unui bloc prelucrarea este tratata de catre
handler-ul de exceptie corespunzator
sectiunii de exceptii din acelasi bloc.
 Daca PL/SQL trateaza cu succes exceptia,
atunci exceptia nu se propaga in blocul
exterior.
 Blocul PL/SQL se incheie cu succes.
64
copyright@www.adrian.runceanu.ro

Manipularea exceptiilor intr-un bloc interior

In urmatorul exemplu survine o eroare in timpul executiei


blocului interior.
Sectiunea EXCEPTION a blocului interior rezolva exceptia
cu succes.
Blocul exterior continua executia in mod obisnuit.
BEGIN -- outer block
………………
BEGIN -- inner block
……. -- exception_name occurs here
…….
EXCEPTION
WHEN exception_name THEN -- handled here
……..
END; -- inner block terminates successfully
…… -- outer block continues execution
END;
65
copyright@www.adrian.runceanu.ro

2. Propagarea exceptiilor catre un bloc


exterior
 In cazul in care apare o exceptie in sectiunea
executabila a blocului interior si nu este nici
un handler de exceptie corespunzator, blocul
PL/SQL se incheie cu insucces si exceptia
este propagata in blocul imediat exterior.
 In acest exemplu apare o eroare in timpul
executiei blocului interior.
 Sectiunea EXCEPTION a blocului interior nu
rezolva exceptia.
 Blocul interior se incheie fara succes si
PL/SQL transmite exceptia blocului exterior.
 Sectiunea EXCEPTION a blocului exterior
manipuleaza cu succes exceptia. 66
copyright@www.adrian.runceanu.ro

7. Domeniul de aplicare a exceptiilor


in blocurile imbricate
BEGIN -- outer block
……
BEGIN -- inner block
……. – exception_name occurs here
…….
END; -- inner block terminates unsuccessfully
…….. -- Remaining code in outer block’s executable
…… -- section is skipped
EXCEPTION
WHEN exception_name THEN – outer block handles
the exception
…………
END;
67
copyright@www.adrian.runceanu.ro

Propagarea exceptiilor intr-un subbloc


 Daca PL/SQL intalneste o exceptie si blocul
curent nu are un handler pentru aceasta
exceptie, exceptia se propaga in blocul imediat
exterior pana cand gaseste un handler.
 Atunci cand exceptia se propaga in blocul
exterior, actiunile executabile ramase in acel
bloc sunt ignorate.
 Un avantaj al acestui lucru este ca puteti sa
adaugati instructiuni care necesita propriile
manipulari de erori, in blocurile proprii.
 Daca nici unul dintre aceste blocuri nu rezolva
exceptia atunci apare o exceptie netratata in
mediul gazda (de exemplu Application
Express). 68
copyright@www.adrian.runceanu.ro

Întrebări?

69
Tehnici de programare cu baze de
date

#4 PL/SQL
Instrucţiuni în PL/SQL

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 4

Instrucţiuni în PL/SQL

2
copyright@www.adrian.runceanu.ro

Cuprins
Instrucţiuni în PL/SQL
1. Instrucţiunea de atribuire
2. Instrucţiuni alternative
3. Instrucţiuni repetitive

3
copyright@www.adrian.runceanu.ro

Instrucţiuni în PL/SQL
Orice program poate fi scris utilizând
structuri de control de bază care sunt
combinate în diferite moduri pentru
rezolvarea problemei propuse.
PL/SQL dispune de comenzi ce permit controlul
execuţiei unui bloc.
Instrucţiuni PL/SQL:
1. de atribuire (:=)
2. condiţionale (IF, CASE)
3. repetitive (LOOP, WHILE, FOR)
4. de salt (GOTO, EXIT)
5. instrucţiunea vidă (NULL)
4
copyright@www.adrian.runceanu.ro

1. Instructiunea de atribuire
 Instrucţiunea de atribuire se realizează
cu ajutorul operatorului de asignare (:=)
şi are forma generală

variabila := expresie

 Comanda respectă proprietăţile


instrucţiunii de atribuire din clasa LG3.
 De remarcat că nu poate fi asignată
valoarea null unei variabile care a fost
declarată NOT NULL. 5
copyright@www.adrian.runceanu.ro

Exemplu:
Următorul exemplu prezintă modul în care
acţionează instrucţiunea de atribuire în cazul
unor tipuri de date particulare.

DECLARE
beta EMP%ROWTYPE;
gama EMP%ROWTYPE;
cursor epsilon IS SELECT * FROM EMP;
delta epsilon%ROWTYPE;
BEGIN
beta := gama; -- corect
DBMS_OUTPUT.PUT_LINE(beta);
gama := delta; -- incorect???-testati!
DBMS_OUTPUT.PUT_LINE(gama);
END;
6
copyright@www.adrian.runceanu.ro

7
copyright@www.adrian.runceanu.ro

Cuprins
Instrucţiuni în PL/SQL
1. Instrucţiunea de atribuire
2. Instrucţiuni alternative
3. Instrucţiuni repetitive

8
copyright@www.adrian.runceanu.ro

2. Instructiuni alternative
 Un program PL/SQL poate executa diferite
porţiuni de cod, în funcţie de rezultatul unui
test.
 Instrucţiunile care realizează acest lucru sunt
cele condiţionale (IF, CASE).

 Structura instrucţiunii IF în PL/SQL este


similară instrucţiunii IF din alte limbaje
procedurale, permiţând efectuarea unor
acţiuni în mod selectiv, în funcţie de anumite
condiţii.
9
copyright@www.adrian.runceanu.ro

Instrucţiunea IF-THEN-ELSIF are


următoarea formă sintactică:
IF condiţie1 THEN
secvenţa_de_comenzi_1
[ELSIF condiţie2 THEN
secvenţa_de_comenzi_2]

[ELSE
secvenţa_de_comenzi_n]
END IF;

10
copyright@www.adrian.runceanu.ro

 O secvenţă de comenzi din IF este executată


numai în cazul în care condiţia asociată este
TRUE.

 Atunci când condiţia este FALSE sau NULL,


secvenţa nu este executată.

 Dacă pe ramura THEN se doreşte verificarea


unei alternative, se foloseşte ramura ELSIF
(atenţie, nu ELSEIF) cu o nouă condiţie.

 Este permis un număr arbitrar de opţiuni


ELSIF, dar poate apărea cel mult o clauză
ELSE. Aceasta se referă la ultimul ELSIF.
11
copyright@www.adrian.runceanu.ro

Instructiunea IF simpla

DECLARE
v_myage NUMBER:=31;
BEGIN
IF v_myage < 11 THEN
DBMS_OUTPUT.PUT_LINE(' I am a
child ');
END IF;
END;

12
copyright@www.adrian.runceanu.ro

Instructiunea IF THEN ELSE

DECLARE
v_myage NUMBER:=31;
BEGIN
IF v_myage < 11 THEN
DBMS_OUTPUT.PUT_LINE(' I am a child ');
ELSE
DBMS_OUTPUT.PUT_LINE(' I am not a child ');
END IF;
END;

13
copyright@www.adrian.runceanu.ro
Clauza IF ELSIF ELSE
DECLARE
v_myage NUMBER:=31;
BEGIN
IF v_myage < 11 THEN
DBMS_OUTPUT.PUT_LINE('I
am a child');
ELSIF v_myage < 20 THEN
DBMS_OUTPUT.PUT_LINE('I
am young');
ELSIF v_myage < 30 THEN
DBMS_OUTPUT.PUT_LINE('I
am in my twenties');
ELSIF v_myage < 40 THEN

DBMS_OUTPUT.PUT_LINE('I
am in my thirties');
ELSE
DBMS_OUTPUT.PUT_LINE('I
am always young ');
END IF;
END;

14
copyright@www.adrian.runceanu.ro

 Daca instructiunea IF contine mai multe


clauze si o conditie este evaluata ca FALSE
sau NULL, atunci controlul se transfera
urmatoarei clauze.

 Conditiile sunt evaluate una cate una


incepand cu prima.

 Daca toate conditiile sunt FALSE sau NULL,


atunci sunt executate instructiunile din clauza
ELSE.

 Clauza ELSE este optionala.

15
copyright@www.adrian.runceanu.ro

Instructiunea IF cu expresii multiple


O instructiune IF poate avea multiple expresii
conditionale legate prin operatori logici cum ar fi:
AND, OR, NOT.
De exemplu:
DECLARE
v_myage NUMBER := 10;
v_myfirstname VARCHAR2(11) :=
'Christopher';
BEGIN
IF v_myfirstname ='Christopher' AND v_myage <
11 THEN
DBMS_OUTPUT.PUT_LINE(' I am a child
named Christopher');
END IF;
END;
16
copyright@www.adrian.runceanu.ro

17
copyright@www.adrian.runceanu.ro

Valorile NULL in instructiunile IF


In urmatorul exemplu variabila v_myage este declarata
dar nu este initializata.
Conditia din instructiunea IF intoarce NULL si nu TRUE
sau FALSE.
In acest caz controlul este preluat de ELSE deoarece
exact ca si FALSE, NULL nu este TRUE.
DECLARE
v_myage NUMBER; Variabila
are
BEGIN
valoarea
IF v_myage < 11 THEN NULL
DBMS_OUTPUT.PUT_LINE(' I am a child ');
ELSE
DBMS_OUTPUT.PUT_LINE(' I am not a child ');
END IF;
END;

18
copyright@www.adrian.runceanu.ro

Valoarea
NULL
preda
controlul pe
ramura
ELSE

19
copyright@www.adrian.runceanu.ro

Folosirea valorilor NULL

Atunci cand lucram cu valorile null putem evita


cateva greseli uzuale retinand urmatoarele
reguli:
1. Comparatiile obisnuite care implica null
intotdeauna produc null
2. Aplicand operatorul logic NOT unui null
produce null
3. In instructiunile conditionale daca o conditie
produce null acesta se comporta ca si cand
ar fi FALSE si secventa de instructiuni
asociata nu se executa.

20
copyright@www.adrian.runceanu.ro

Fie urmatorul exemplu:


x := 5;
y := NULL;
……
IF x != y THEN ……. ----- Rezultatul este
NULL deci nu este TRUE si secventa de
instructiuni nu se executa
END IF;
Conditia de la IF produce NULL si secventa
de instructiuni nu se executa.

21
copyright@www.adrian.runceanu.ro

Fie urmatorul exemplu:


a := NULL;
b := NULL;
……….
IF a = b THEN … --- returneaza NULL
END IF;
Rezultatul este NULL, deci nu se executa
secventa de instructiuni.

22
copyright@www.adrian.runceanu.ro

Concluzii – instr. IF
Reguli de utilizare a instructiunilor IF
1. Se pot efectua operatii selectiv atunci cand
este intalnita o conditie anume
2. Atunci cand scriem codul trebuie sa ne
amintim cum se scriu cuvintele cheie
◦ ELSIF – un singur cuvant
◦ END IF – doua cuvinte
3. Daca conditia de control booleana este
TRUE atunci se executa secventa de
instructiuni asociata; daca conditia de control
booleana este FALSE sau NULL atunci
secventa de instructiuni nu se executa.
4. Sunt permise oricate clauze ELSIF. 23
copyright@www.adrian.runceanu.ro

Instructiunea CASE

INSTRUCTIUNEA CASE
 Instructiunile CASE sunt asemanatoare
cu instructiunile IF, dar de obicei sunt mai
usor de scris si de citit.
 Expresiile CASE sunt functii care intorc o
valoare numerica intr-o variabila.

24
copyright@www.adrian.runceanu.ro

Daca avem urmatoarea instructiune IF, ce observam?


DECLARE
v_numvar NUMBER;
BEGIN
……
IF v_numvar = 5 THEN statement_1; statement_2;
ELSIF v_numvar = 10 THEN statement_3;
ELSIF v_numvar = 12 THEN statement_4; statement_5;
ELSIF v_numvar = 27 THEN statement_6;
ELSIF v_numvar ... ….
ELSE statement_15;
END IF;
……………
END;
Toate conditiile testeaza aceeasi variabila v_numvar.
Si codul este repetitiv – variabila v_numvar este folosita de
multe ori.

25
copyright@www.adrian.runceanu.ro

Pentru a face acelasi lucru se poate folosi


urmatoarea instructiune CASE:
DECLARE
v_numvar NUMBER;
BEGIN
………..
CASE v_numvar
WHEN 5 THEN statement_1; statement_2;
WHEN 10 THEN statement_3;
WHEN 12 THEN statement_4; statement_5;
WHEN 27 THEN statement_6;
WHEN ...
ELSE statement_15;
END CASE;
…………
END;
Evident este mai usor de scris, iar variabila v_numvar este
referita o singura data.
26
copyright@www.adrian.runceanu.ro

Expresiile CASE
Uneori vrem sa atribuim o valoare unei variabile
care depinde de valoarea altei variabile.
DECLARE
v_out_var VARCHAR2(15);
v_in_var NUMBER;
BEGIN
………………
IF v_in_var = 1 THEN v_out_var := 'Low value';
ELSIF v_in_var = 50 THEN v_out_var :=
'Middle value';
ELSIF v_in_var = 99 THEN v_out_var := 'High
value';
ELSE v_out_var := 'Other value';
END IF;
END;
Din nou codul este foarte repetitiv.
27
copyright@www.adrian.runceanu.ro

Acelasi lucru se poate realiza cu urmatoarea expresie


CASE.
DECLARE
v_out_var VARCHAR2(15);
v_in_var NUMBER;
BEGIN
…………..
v_out_var :=
CASE v_in_var
WHEN 1 THEN 'Low value'
WHEN 50 THEN 'Middle value'
WHEN 99 THEN 'High value'
ELSE 'Other value'
END;
………..
END;

28
copyright@www.adrian.runceanu.ro

O expresie CASE selecteaza un rezultat


dintr-o serie de rezultate si-l returneaza intr-o
variabila.

variable_name :=
CASE selector
WHEN expression1 THEN result1
WHEN expression2 THEN result2
………….
WHEN expressionN THEN resultN
[ELSE resultN+1]
END;

29
copyright@www.adrian.runceanu.ro

EXEMPLU 1

DECLARE
v_grade CHAR(1) := 'A';
v_appraisal VARCHAR2(20);
BEGIN
v_appraisal :=
CASE v_grade
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade: '|| v_grade ||'
Appraisal ' || v_appraisal);
END;
Ce se afiseaza?
30
copyright@www.adrian.runceanu.ro

31
copyright@www.adrian.runceanu.ro

EXEMPLU 2

DECLARE
v_out_var VARCHAR2(15);
v_in_var NUMBER := 20;
BEGIN
v_out_var :=
CASE v_in_var
WHEN 1 THEN 'Low value'
WHEN v_in_var THEN 'Same value'
WHEN 20 THEN 'Middle value'
ELSE 'Other value'
END;
DBMS_OUTPUT.PUT_LINE(v_out_var);
END;

Ce se afiseaza?
32
copyright@www.adrian.runceanu.ro

33
copyright@www.adrian.runceanu.ro

Expresiile CASE de cautare

PL/SQL furnizeaza expresia CASE de


cautare care are urmatoarea forma:

CASE
WHEN search_condition1 THEN result1
WHEN search_condition2 THEN result2
………………………
WHEN search_conditionN THEN resultN
[ELSE resultN+1]
END;

34
copyright@www.adrian.runceanu.ro

O expresie CASE de cautare nu are selector.


De asemenea, clauzele WHEN contin conditii de cautare care au
valoare booleana, nu expresii care dau valori de orice tip.

EXEMPLU

DECLARE
v_grade CHAR(1) := 'B';
v_appraisal VARCHAR2(20);
BEGIN
v_appraisal :=
CASE
WHEN v_grade = 'A' THEN 'Excellent'
WHEN v_grade IN ('B','C') THEN 'Good'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade: '|| v_grade ||' Appraisal '
|| v_appraisal);
END;

35
copyright@www.adrian.runceanu.ro

36
copyright@www.adrian.runceanu.ro

Prin ce difera expresiile CASE de


instructiunile CASE?

1) Expresiile CASE:

a) Expresiile CASE returneaza o


valoare intr-o variabila

b) Expresiile CASE se incheie cu END;

c) O expresie CASE este o instructiune


PL/SQL singulara
37
copyright@www.adrian.runceanu.ro

DECLARE
v_grade CHAR(1) := 'C';
v_appraisal VARCHAR2(20);
BEGIN
v_appraisal :=
CASE
WHEN v_grade = 'A' THEN
'Excellent'
WHEN v_grade IN ('B','C') THEN
'Good'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade: '|| v_grade
|| ' Appraisal ' || v_appraisal);
END;
38
copyright@www.adrian.runceanu.ro

39
copyright@www.adrian.runceanu.ro

2) Instructiunile CASE:

a) Instructiunile CASE evalueaza


conditii si executa operatii

b) O instructiune CASE poate contine


mai multe instructiuni PL/SQL

c) Instructiunile CASE se incheie cu


END CASE

40
copyright@www.adrian.runceanu.ro

DECLARE
v_grade CHAR(1) := 'A';
BEGIN
CASE
WHEN v_grade = 'A' THEN
DBMS_OUTPUT.PUT_LINE ('Excellent');
WHEN v_grade IN ('B','C') THEN
DBMS_OUTPUT.PUT_LINE ('Good');
ELSE
DBMS_OUTPUT.PUT_LINE('No such
grade');
END CASE;
END;

41
copyright@www.adrian.runceanu.ro

42
copyright@www.adrian.runceanu.ro

TABELE LOGICE

AND TRUE FALSE NULL OR TRUE FALSE NULL NOT

TRUE TRUE FALSE NULL TRUE TRUE TRUE TRUE TRUE FALSE

FALSE FALSE FALSE FALSE FALSE TRUE FALSE NULL FALSE TRUE

NULL NULL FALSE NULL NULL TRUE NULL NULL NULL NULL

43
copyright@www.adrian.runceanu.ro

Cuprins
Instrucţiuni în PL/SQL
1. Instrucţiunea de atribuire
2. Instrucţiuni alternative
3. Instrucţiuni repetitive

44
copyright@www.adrian.runceanu.ro

3. Instructiuni repetitive
Structura repetitiva presupune repetarea
unor operatii pana cand se ajunge la o
conditie de oprire.

PL/SQL are trei tipuri de structuri repetitive:


1) Instructiunea LOOP de baza (basic LOOP)
– repeta operatii fara o conditie generala
2) Instructiunea FOR – repetarea unor operatii
pe baza unui contor
3) Instructiunea WHILE – repetarea unor
operatii pe baza unei conditii

45
copyright@www.adrian.runceanu.ro

3.1.Instructiunea LOOP
Basic LOOP (structura repetitiva de baza)

 Cea mai simpla forma a unei instructiuni


LOOP este basic LOOP care cuprinde o
secventa de instructiuni intre cuvintele cheie
LOOP si END LOOP.
 In aceasta instructiune secventa de
instructiuni se va executa cel putin o data.
 De fiecare data cand executia ajunge la END
LOOP controlul este returnat instructiunii
LOOP corespunzatoare de mai sus.

46
copyright@www.adrian.runceanu.ro

3.1.Instructiunea LOOP
Sintaxa:
LOOP
statement1;
……………
EXIT [WHEN condition];
END LOOP;
 Un basic loop permite executarea instructiunilor sale cel
putin o data chiar daca conditia EXIT este deja intalnita
la intrarea in bucla.
 Fara instructiunea EXIT instructiunea LOOP ar fi
infinita.
47
Exemplu: copyright@www.adrian.runceanu.ro

DECLARE
a NUMBER:=1;
BEGIN
LOOP
dbms_output.put_line(a);
a:=a+1;
EXIT WHEN a>5;
END LOOP;
END;

48
copyright@www.adrian.runceanu.ro

Instructiunea EXIT

 Instructiunea EXIT este folosita pentru a


incheia un LOOP.

 Controlul este transmis instructiunii care


urmeaza dupa END LOOP.

 Se poate folosi EXIT:


◦ fie ca actiune intr-un IF
◦ fie ca o instructiune intr-un LOOP
49
copyright@www.adrian.runceanu.ro

Exemplu:

DECLARE
monthly_value NUMBER:=10;
daily_value NUMBER:=1;
BEGIN
LOOP
monthly_value := daily_value * 31;
daily_value := daily_value + 1;
EXIT WHEN monthly_value > 4000;
END LOOP;
DBMS_OUTPUT.PUT_LINE(monthly_value);
END;

50
copyright@www.adrian.runceanu.ro

51
copyright@www.adrian.runceanu.ro

 Instructiunea EXIT trebuie plasata in


interiorul unui LOOP.
 Daca o conditie EXIT este plasata la
inceputul unui LOOP (inaintea oricarei
instructiuni executabile) si daca conditia
este initial TRUE atunci se iese din
LOOP si celelalte instructiuni din LOOP
nu se mai executa
 Un BASIC LOOP poate sa contina mai
multe instructiuni EXIT, dar ar trebuie sa
avem un singura iesire (EXIT).

52
copyright@www.adrian.runceanu.ro

Instructiunea EXIT WHEN


 Clauza WHEN se foloseste pentru a permite o terminare
conditionala a instructiunii LOOP.
 Atunci cand este intalnita instructiunea EXIT este evaluata
conditia din clauza WHEN.
 Daca conditia ne da ca rezultat TRUE, atunci se incheie
instructiunea LOOP si controlul este transmis instructiunii care
urmeaza dupa LOOP.
DECLARE
v_counter NUMBER := 1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE('The square of
'||v_counter||' is: '|| POWER(v_counter,2));
v_counter :=v_counter + 1;
EXIT WHEN v_counter > 10;
END LOOP;
END;
53
copyright@www.adrian.runceanu.ro

54
copyright@www.adrian.runceanu.ro

3.2.Instructiunea WHILE
 Instructiunea WHILE presupune repetarea
unei secvente de instructiuni pana cand o
conditie de control nu mai este adevarata.

 Conditia este evaluata la inceputul fiecarei


iteratii.

 Instructiunea se incheie atunci cand conditia


este FALSE sau NULL.

 Daca conditia este FALSE sau NULL de la


inceput atunci nu se executa nici o iteratie. 55
copyright@www.adrian.runceanu.ro

3.2.Instructiunea WHILE
Sintaxa

WHILE conditie LOOP


instructiune1;
instructiune 2;
……………..
END LOOP;

56
copyright@www.adrian.runceanu.ro

3.2.Instructiunea WHILE
 Conditia este o variabila sau o expresie
booleana (TRUE, FALSE sau NULL).

 instructiune1, instructiune2,….. sunt


grupari de una sau mai multe instructiuni

 Daca variabilele implicate in conditii nu se


schimba pe parcursul instructiunii WHILE,
atunci conditia ramane la valoarea TRUE
si instructiunea se executa la infinit.
57
copyright@www.adrian.runceanu.ro

3.2.Instructiunea WHILE
Exemplu:
DECLARE
n_num NUMBER;
b_run BOOLEAN := TRUE;
BEGIN
n_num := 1;
WHILE b_run
LOOP
DBMS_OUTPUT.put_line (n_num || ' Times');
n_num := n_num + 1;
IF n_num > 5
THEN
b_run := FALSE;
END IF;
END LOOP;
END;
58
copyright@www.adrian.runceanu.ro

59
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR

Instructiunea FOR are o structura


asemanatoare unui basic loop, dar are in
plus o instructiune de control inainte de
cuvantul cheie LOOP pentru a seta
numarul de iteratii pe care le executa
PL/SQL.

60
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR
Sintaxa

FOR counter IN [REVERSE]


lower_bound .. upper_bound LOOP
instructiune 1;
instructiune 2;
………………..
END LOOP;
Se foloseste FOR pentru a da comenzi rapide
de testare a numarului de iteratii
61
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR
 Nu se declara contorul; el este declarat implicit
 Contorul este declarat implicit intreg si
valoarea sa este marita sau micsorata
(valoarea este micsorata daca se foloseste
cuvantul cheie REVERSE) automat cu 1 la
fiecare iteratie pana cand este atinsa valoarea
finala.
 Intotdeauna valoarea mai mica lower_bound
este prima specificata:
◦ lower_bound specifica valoarea minima a
domeniului de valori ale contorului
◦ upper_bound specifica valoarea maxima a
domeniului de valori ale contorului
62
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR
Exemplu:

BEGIN
FOR c IN (SELECT EMPNO, ENAME, SAL
FROM emp
WHERE deptno = 10)
LOOP
DBMS_OUTPUT.PUT_LINE ('Salary for the
employee ' || c.ename || ' is: ' || c.sal);
END LOOP;
END;

63
copyright@www.adrian.runceanu.ro

64
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR
Reguli de folosire a instructiunii FOR

 Contorul poate fi folosi numai in interiorul


instructiunii; el este nedeclarat in afara ei
 Nu putem referi contorul pentru a-i atribui o
valoare
 Valorile initiale si finale ale contorului nu pot fi
NULL
 Cand scriem un FOR lower_bound si
upper_bound nu trebuie sa fie neaparat
literali numerici ci pot fi si expresii ce se
convertesc la valori numerice.
65
copyright@www.adrian.runceanu.ro

3.3.Instructiunea FOR
Exemplu:
DECLARE
v_lower NUMBER := 1;
v_upper NUMBER := 100;

BEGIN
FOR i IN v_lower..v_upper LOOP
…………………..
END LOOP;
END;

66
copyright@www.adrian.runceanu.ro

Concluzii
 Se foloseste un basic loop atunci cand
instructiunile trebuie sa se execute cel
putin o data

 Se foloseste instructiunea WHILE


atunci cand conditia trebuie sa fie
evaluata la inceputul fiecarei iteratii

 Se foloseste instructiunea FOR atunci


cand numarul de iteratii este cunoscut.
67
copyright@www.adrian.runceanu.ro

Întrebări?

68
Tehnici de programare cu baze de
date

#5 PL/SQL
Cursori în PL/SQL (partea I-a)

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 5

Cursori în PL/SQL
(partea I)

2
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. Structura repetitivă – instrucţiuni


imbricate
2. Cursori expliciţi – introducere
3. Folosirea atributelor cursorilor
expliciţi

3
copyright@www.adrian.runceanu.ro

1. Structura repetitivă – instrucţiuni


imbricate
Instructiunile repetitive se pot imbrica pe mai
multe nivele.
Exemple:
1)
BEGIN
FOR v_outerloop IN 1..3 LOOP
FOR v_innerloop IN REVERSE 1..5 LOOP
DBMS_OUTPUT.PUT_LINE('Outer loop
is:'||v_outerloop||' and inner loop is:
'||v_innerloop);
END LOOP;
END LOOP;
END;
4
copyright@www.adrian.runceanu.ro

5
copyright@www.adrian.runceanu.ro
2) Urmatoarea instructiune contine o conditie EXIT in
structurile repetitive imbricate
DECLARE
v_outer_done CHAR(3) := 'NO';
v_inner_done CHAR(3) := 'NO';
BEGIN
LOOP -- outer loop

LOOP -- inner loop

… -- pas A
EXIT WHEN v_inner_done = 'YES';
………………
END LOOP;

EXIT WHEN v_outer_done = 'YES';

END LOOP;
END;
Ce se intampla daca vrem sa iesim dintr-un loop la pasul A?
6
copyright@www.adrian.runceanu.ro

ETICHETE

DECLARE

BEGIN
<<outer_loop>>
LOOP -- outer loop

<<inner_loop>>
LOOP -- inner loop
EXIT outer_loop WHEN ... -- iesire din ambele loop-uri
EXIT WHEN v_inner_done = 'YES';

END LOOP;

EXIT WHEN v_outer_done = 'YES';

END LOOP;
END;

7
copyright@www.adrian.runceanu.ro

1. Structura repetitivă – instrucţiuni


imbricate
 Denumirile etichetelor dintr-un loop respecta
aceleasi reguli ca orice identificator.
 O eticheta este plasata inaintea unei
instructiuni fie pe aceeasi linie, fie pe linie
separata.
 In instructiunile FOR si WHILE eticheta se
plaseaza inainte de FOR sau WHILE cu
delimitatorii de eticheta ( <<label>> ).
 Daca instructiunea loop este etichetata,
denumirea etichetei poate fi inclusa optional
dupa END LOOP pentru claritate.
8
copyright@www.adrian.runceanu.ro

Exemplu – La instructiunea basic loop se pune eticheta inainte de


cuvantul LOOP intre delimitatorii de eticheta.

DECLARE
v_outerloop PLS_INTEGER :=0;
v_innerloop PLS_INTEGER :=5;
BEGIN
<<Outer_loop>>
LOOP
v_outerloop := v_outerloop + 1;
v_innerloop := 5;
EXIT WHEN v_outerloop > 3;
<<Inner_loop>>
LOOP
DBMS_OUTPUT.PUT_LINE('Outer loop
is:'||v_outerloop||' and inner loop is: '||v_innerloop);
v_innerloop := v_innerloop - 1;
EXIT WHEN v_innerloop =0;
END LOOP Inner_loop;
END LOOP Outer_loop;
END;

9
copyright@www.adrian.runceanu.ro

10
copyright@www.adrian.runceanu.ro

Exemplu – loop-uri imbricate si etichete

…BEGIN
<<Outer_loop>>
LOOP
v_counter := v_counter+1;
EXIT WHEN v_counter>10;
<<Inner_loop>>
LOOP

EXIT Outer_loop WHEN v_total_done = 'YES';
-- iese din ambele loop-uri
EXIT WHEN v_inner_done = 'YES';
-- iese numai din inner loop

END LOOP Inner_loop;

END LOOP Outer_loop;
END;
11
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. Structura repetitivă – instrucţiuni


imbricate
2. Cursori expliciţi – introducere
3. Folosirea atributelor cursorilor
expliciţi

12
copyright@www.adrian.runceanu.ro

2. Cursori expliciţi – introducere

 Se stie ca o instrucţiune SQL într-un bloc


PL/SQL rulează cu succes dacă dă un singur
rezultat.
 Dar dacă avem nevoie să scriem o
instrucţiune SELECT care să dea mai multe
rezultate?
 Dacă de exemplu avem de facut un raport cu
toţi angajaţii?
 Pentru a obţine mai multe rezultate trebuie să
declarăm şi să folosim un cursor explicit.
13
copyright@www.adrian.runceanu.ro

2. Cursori expliciţi – introducere


Cursorii şi domeniile lor de context
 Serverul Oracle aloca zone private de
memorie numite zone (domenii) de context
pentru a stoca datele prelucrate de o
instructiune SQL.
 Fiecare zona de context (si prin urmare fiecare
instructiune SQL) are un cursor asociat.
 Ne putem gandi la un cursor ca la o eticheta a
zonei de context sau un pointer al zonei de
context.
 De fapt un cursor este si o eticheta si un
pointer.
14
copyright@www.adrian.runceanu.ro

2. Cursori expliciţi – introducere

Cursori impliciţi şi cursori expliciţi


 Cursorii impliciţi – sunt definiti automat de
Oracle pentru toate instructiunile DML ale
SQL (INSERT, UPDATE, DELETE si
MERGE) si pentru toate instructiunile SQL
care returneaza un singur rand
 Cursorii expliciţi – declaraţi de programator
pentru interogările care returnează mai mult
de un rand. Cursorii expliciţi se pot folosi
pentru a denumi o zonă de context şi pentru
a accesa datele stocate în ea.
15
copyright@www.adrian.runceanu.ro

Limitele cursorilor impliciţi


Fie urmatorul exemplu:
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal
INTO v_sal
FROM emp;
DBMS_OUTPUT.PUT_LINE(' Salary is :
'||v_sal);
END;
Se va afisa un mesaj de eroare, deoarece
tabela employees are mai multe linii

16
copyright@www.adrian.runceanu.ro

2. Cursori expliciţi – introducere

 Cu un cursor explicit putem extrage randuri


multiple din tabela, avand un pointer catre
fiecare rand extras si putem lucra cu un rand
la un moment dat.

 Motivele pentru care folosim cursorii expliciti


sunt:
1. Este singura modalitate în PL/SQL de a folosi mai
mult de un rând dintr-o tabelă
2. Fiecare rând este preluat de către o instrucţiune de
program separata, dând programatorului mai mult
control în prelucrarea rândurilor
17
copyright@www.adrian.runceanu.ro

Exemplu de cursor explicit:


Cursorul se foloseste pentru numele tarilor si populatiile pentru
continentul Africa
DECLARE
CURSOR eba_population_cursor IS
SELECT name, population
FROM eba_countries where region_id = 40;
v_country_name eba_countries.name%TYPE;
v_population eba_countries.population%TYPE;
BEGIN
OPEN eba_population_cursor;
LOOP
FETCH eba_population_cursor INTO v_country_name,
v_population;
EXIT WHEN eba_population_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_country_name||'
'||v_population);
END LOOP;
CLOSE eba_population_cursor;
END;
18
copyright@www.adrian.runceanu.ro

Exemplu de cursor explicit:


Cursorul se foloseste pentru numele tarilor si populatiile pentru
continentul Africa

19
copyright@www.adrian.runceanu.ro

2. Cursori expliciţi – introducere


Operaţii – cursori expliciţi

 O mulţime de rânduri furnizate de o interogare


multiple-row este denumită mulţime activă (active
set) şi este stocată în zona de context.
 Dimensiunea sa este numărul de rânduri care
îndeplinesc criteriul de căutare.
 Ne putem imagina zona de context ca fiind o cutie,
conţinutul cutiei fiind mulţimea activă.
 Pentru a prelua date trebuie deschisă (OPEN) cutia şi
sunt preluate (FETCH) rândurile din cutie, pe rând,
câte unul.
 Când am terminat trebuie să închidem (CLOSE) cutia.
20
copyright@www.adrian.runceanu.ro

Cursor explicit:

1. Deschiderea cursorului

2. Preluarea a câte unui rând

3. Închiderea cursorului

21
copyright@www.adrian.runceanu.ro

Declararea şi controlul cursorilor


expliciţi
Paşii pentru utilizarea cursorilor expliciţi sunt:
1. Declarare (DECLARE) – se face in sectiunea
declarativa si se denumeste setul activ
2. Deschidere (OPEN) – Instructiunea OPEN
executa interogarea asociata cursorului,
identifica setul de rezultate si pozitioneaza
cursorul inainte de primul rand.
3. Preluare (FETCH) – Instructiunea FETCH
extrage randul curent si avanseaza cursorul la
randul urmator.
4. Închiderea (CLOSE) cursorului se face dupa
ce a fost prelucrat ultimul rand. Instructiunea
CLOSE dezactiveaza cursorul. 22
copyright@www.adrian.runceanu.ro

1. Declararea unui cursor

 Setulactiv al unui cursor este determinat de


instructiunea SELECT din declararea
cursorului.
Sintaxa
CURSOR cursor_name IS
select_statement;
unde:
cursor_name - reprezinta un identificator
PL/SQL
select_statement; - reprezinta o instructiune
SELECT fara o clauza INTO 23
copyright@www.adrian.runceanu.ro

1. Declararea unui cursor


Exemplu 1
Cursorul emp_cursor este declarat
pentru a extrage coloanele empno si ename
pentru angajatii care lucreaza in
departamentul pentru care deptno este 30.
DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM WHERE deptno =30;

24
copyright@www.adrian.runceanu.ro

1. Declararea unui cursor


Exemplu 2
Cursorul dept_cursor este declarat
pentru a extrage toate informatiile pentru
departamentele care au loc 1700. Preluam si
prelucram randurile alfabetic dupa dname.
DECLARE
CURSOR dept_cursor IS
SELECT *
FROM dept
WHERE loc = 1700
ORDER BY dname;

25
copyright@www.adrian.runceanu.ro

1. Declararea unui cursor


Exemplu 3
O instructiune SELECT in declararea unui cursor poate
include join-uri, functii de grup si subinterogari.
Acest exemplu extrage fiecare departament care are
cel putin doi angajati furnizand numele
departamentului si numarul de angajati.
DECLARE
CURSOR dept_emp_cursor IS
SELECT dname, COUNT(*) AS how_many
FROM dept d, emp e
WHERE d.deptno = e.deptno
GROUP BY d.dname
HAVING COUNT(*) > 1;

26
copyright@www.adrian.runceanu.ro

Reguli de declarare a unui cursor


1. Nu se include clauza INTO in declararea
cursorului deoarece va aparea mai tarziu in
instructiunea FETCH
2. Daca randurile se prelucreaza intr-o ordine
specificata atunci se foloseste clauza
ORDER BY
3. Cursorul poate fi orice instructiune SELECT
valida ce poate include join-uri,
subinterogari etc.
4. Daca declararea unui cursor se refera la
variabile PL/SQL, atunci aceste variabile
trebuie declarate inainte de cursor.
27
copyright@www.adrian.runceanu.ro

Cursor explicit:

1. Deschiderea cursorului

2. Preluarea a câte unui rând

3. Închiderea cursorului

28
copyright@www.adrian.runceanu.ro

2. Deschiderea unui cursor


 Instructiunea OPEN executa interogarea asociata
cursorului, identifica multimea activa si pozitioneaza
pointerul cursorului catre primul rand.
 Instructiunea OPEN este inclusa in partea executabila a
unui bloc PL/SQL.
DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE deptno =30;

BEGIN
OPEN emp_cursor;
… 29
copyright@www.adrian.runceanu.ro

2. Deschiderea unui cursor


Instructiunea OPEN efectueaza
urmatoarele 3 operatii:

1. Aloca memorie pentru zona de context


(creeaza “cutia”)

2. Executa instructiunea SELECT din


declararea cursorului, returnand rezultatele
in multimea activa (umple „cutia” cu date)

3. Pozitioneaza pointerul la primul rand din


multimea activa (deschide “cutia”)
30
copyright@www.adrian.runceanu.ro

Cursor explicit:

1. Deschiderea cursorului

2. Preluarea a câte unui rând

3. Închiderea cursorului

31
copyright@www.adrian.runceanu.ro

3. Preluarea datelor de la cursor

 Instructiunea FETCH extrage randuri de la


cursor, unul singur la un moment dat.

 Dupa fiecare preluare, cursorul avanseaza la


urmatorul rand in multimea activa.

32
copyright@www.adrian.runceanu.ro

3. Preluarea datelor de la cursor


Doua variabile v_empno si v_lname sunt
declarate pentru a retine valorile preluate de cursor.
DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE depno =10;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_empno, v_ename;
DBMS_OUTPUT.PUT_LINE(v_empno ||' '||v_ename);

END;
33
copyright@www.adrian.runceanu.ro
Pentru a prelua toate randurile avem nevoie de loop-uri.

DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE deptno=30;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_empno,
v_ename;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_empno ||'
'||v_ename);
END LOOP;
END;
34
copyright@www.adrian.runceanu.ro

35
copyright@www.adrian.runceanu.ro

Reguli pentru preluarea datelor de la


un cursor
1. Trebuie sa includem acelasi numar de variabile
in clauza INTO a instructiunii FETCH ca si
numarul de coloane din instructiunea SELECT,
iar tipurile de date trebuie sa fie compatibile.
2. Corespondenta dintre variabile si coloane
trebuie sa fie de unu la unu.
3. Trebuie sa verificam daca cursorul contine
randuri. Daca o preluare nu capata valori,
atunci nu mai sunt randuri de procesat in
multimea activa si nu se inregistreaza erori.
Ultimul rand este prelucrat din nou.
4. Putem folosi atributul de cursor %NOTFOUND
pentru a testa o conditie de iesire. 36
copyright@www.adrian.runceanu.ro

Cursor explicit:

1. Deschiderea cursorului

2. Preluarea a câte unui rând

3. Închiderea cursorului

37
copyright@www.adrian.runceanu.ro

4. Inchiderea cursorilor

 Instructiunea CLOSE dezactiveaza cursorul,


elibereaza zona de context si zona ramane
nedefinita.

 Cursorul se inchide dupa prelucrarea


completa a instructiunii FETCH.

 Cursorul se poate deschide mai tarziu daca


este nevoie.

38
copyright@www.adrian.runceanu.ro

4. Inchiderea cursorilor
Ne putem gandi la inchiderea cursorului ca
la golirea si inchiderea „cutiei”, deci nu mai
putem lua nimic din continutul ei.

LOOP
FETCH emp_cursor INTO v_empno,
v_ename;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_empno ||'
'||v_ename);
END LOOP;
CLOSE emp_cursor;
END; 39
copyright@www.adrian.runceanu.ro

Reguli pentru închiderea unui cursor


1. Un cursor poate fi redeschis numai daca este
inchis.

2. Dacă încercaţi să preluati date dintr-un cursor


dupa ce a fost inchis atunci apare o exceptie
INVALID_CURSOR

3. Daca mai tarziu redeschidem cursorul atunci


instructiunea SELECT asociata este
executata din nou pentru a reumple zona de
context cu cele mai recente date din baza de
date.
40
copyright@www.adrian.runceanu.ro

Exemplu de cursor explicit:


Cursorul se foloseste pentru numele tarilor si populatiile pentru
continentul Africa
DECLARE
CURSOR eba_population_cursor IS
SELECT name, population
FROM eba_countries where region_id IN(30,34,35);
v_country_name eba_countries.name%TYPE;
v_population eba_countries.population%TYPE;
BEGIN
OPEN eba_population_cursor;
LOOP
FETCH eba_population_cursor INTO v_country_name,
v_population;
EXIT WHEN eba_population_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_country_name||'
'||v_population);
END LOOP;
CLOSE eba_population_cursor;
END;
41
copyright@www.adrian.runceanu.ro

Exemplu de cursor explicit:


Cursorul se foloseste pentru numele tarilor si populatiile pentru
continentul Africa

42
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. Structura repetitivă – instrucţiuni


imbricate
2. Cursori expliciţi – introducere
3. Folosirea atributelor cursorilor
expliciţi

43
copyright@www.adrian.runceanu.ro

3. FOLOSIREA ATRIBUTELOR
CURSORILOR EXPLICITI

 Înregistrările cursorului ne permit să


declarăm o singură variabilă pentru
toate coloanele selectate în cursor.

 Atributele cursorului ne permit să


extragem informaţii cu privire la starea
cursorului explicit.

44
copyright@www.adrian.runceanu.ro

3.1. Cursori şi înregistrări

 Cursorul din urmatorul exemplu este


bazat pe o instructiune SELECT care
extrage doar doua coloane din fiecare
rând al tabelei.

45
copyright@www.adrian.runceanu.ro

DECLARE
v_emp_id emp.empno%TYPE;
v_ename emp.ename%TYPE;
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE deptno =30;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_emp_id,
v_ename;

Dar daca extrage 6 coloane sau 7, 8, 9,…coloane?

46
copyright@www.adrian.runceanu.ro
Urmatorul cursor extrage in intregime randurile din tabela angajati:
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;

v_deptno emp.deptno%TYPE;
CURSOR emp_cursor IS
SELECT * FROM emp
WHERE deptno =30;
BEGIN
OPEN emp_cursor;
LOOP
Am declarat si FETCH emp_cursor
utilizat cate o INTO v_empno, v_ename, v_sal ...v_deptno;
variabila …
pentru fiecare
coloana a
tabelei emp

Este mult de scris si este incomod, nu?


47
copyright@www.adrian.runceanu.ro

Un cod mai simplu pentru a extrage aceleasi


informatii este urmatorul:
DECLARE
CURSOR emp_cursor IS
SELECT *
FROM emp
WHERE deptno =30;
v_emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO
v_emp_record;

48
copyright@www.adrian.runceanu.ro

 Acest cod foloseste %ROWTYPE pentru a


declara o structura de tip inregistrare bazata pe
cursor.
 O înregistrare este un tip de date compus in
PL/SQL.
 O inregistrare este formata din mai multe
campuri, fiecare cu propriul nume si tip de
date.
 Putem referi câmpurile prefixându-le
denumirile de caracterul punct şi denumirea
înregistrării.
 %ROWTYPE declară o înregistrare cu aceleaşi
câmpuri ca şi cursorul pe care se bazează.

49
copyright@www.adrian.runceanu.ro

Exemplu:
DECLARE
CURSOR emp_cursor IS
SELECT empno, ename, sal
FROM emp
WHERE deptno =30;
v_emp_record emp_cursor%ROWTYPE;

v_emp_record.empno v_emp_record.ename v_emp_record.sal
100 King 24000

50
copyright@www.adrian.runceanu.ro

%ROWTYPE este convenabil pentru prelucrarea randurilor din


multimea activa deoarece putem prelua datele intr-o modalitate
mai simpla, folosind inregistrarile.
Exemplu:
DECLARE
CURSOR emp_cursor IS
SELECT * FROM emp
WHERE deptno =30;
v_emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_emp_record;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_record.empno||'-' ||
v_emp_record.ename);
END LOOP;
CLOSE emp_cursor;
END;

51
copyright@www.adrian.runceanu.ro

52
copyright@www.adrian.runceanu.ro

Apelul fiecarui camp al inregistrarii prin specificarea denumirii


campului precedat de constructia .nume_inregistrare

DECLARE
CURSOR emp_dept_cursor IS
SELECT ename, sal, dname
FROM emp e, dept d
WHERE e.deptno = d.deptno;
v_emp_dept_record emp_dept_cursor%ROWTYPE;
BEGIN
OPEN emp_dept_cursor;
LOOP
FETCH emp_dept_cursor INTO v_emp_dept_record;
EXIT WHEN emp_dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_emp_dept_record.ename ||'
– '|| v_emp_dept_record.sal ||' – '|| v_emp_dept_record.dname);
END LOOP;
CLOSE emp_dept_cursor;
END;

53
copyright@www.adrian.runceanu.ro

54
copyright@www.adrian.runceanu.ro

3.2. Atributele cursorilor expliciţi

 Ca şi pentru cursorii impliciţi, sunt câteva


atribute utile pentru a obţine informaţii cu
privire la starea cursorilor expliciţi.

 Aceste atribute ne dau informaţii utile cu


privire la execuţia unei instrucţiuni de
manipulare a cursorului.

55
copyright@www.adrian.runceanu.ro

3.2. Atributele cursorilor expliciţi

Attribute Type Description


%ISOPEN Boolean Evaluates to TRUE if the cursor is open

Evaluates to TRUE if the most recent fetch did not


%NOTFOUND Boolean
return a row
Evaluates to TRUE if the most recent fetch returned a
%FOUND Boolean
row; opposite of %NOTFOUND

%ROWCOUNT Number Evaluates to the total number of rows FETCHed so far

56
copyright@www.adrian.runceanu.ro
a) Atributul %ISOPEN
 Se stie ca putem extrage randuri doar atunci
cand cursorul este deschis.
 Pentru a verifica daca este deschis cursorul
se foloseste atributul %ISOPEN.
 %ISOPEN ne da starea cursorului:
◦ TRUE daca acesta este deschis
◦ si FALSE in caz contrar.

Exemplu:
IF NOT emp_cursor%ISOPEN THEN
OPEN emp_cursor;
END IF;
LOOP
FETCH emp_cursor...
57
copyright@www.adrian.runceanu.ro

De obicei, aceste 2 atribute se folosesc intr-un


loop pentru a determina iesirea din loop.

b) Atributul %ROWCOUNT
 Atributul %ROWCOUNT se foloseste pentru:
1. Pentru prelucrarea unui anumit numar de randuri
2. Pentru a numara randurile preluate intr-un loop
si/sau pentru a determina cand se iese din loop

c) Atributul %NOTFOUND
 Atributul %NOTFOUND se foloseste pentru:
1. Pentru a determina daca interogarea a gasit
randuri care se potrivesc criteriului
2. Pentru a determina cand se face iesirea din loop

58
copyright@www.adrian.runceanu.ro

Exemplu pentru %ROWCOUNT si %NOTFOUND

DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp;
v_emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_emp_record;
EXIT WHEN emp_cursor%ROWCOUNT>10
OR emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_record.empno||' '||
v_emp_record.ename );
END LOOP;
CLOSE emp_cursor;
END;
59
copyright@www.adrian.runceanu.ro

60
Atributele cursorilor expliciti nu pot fi folosite directcopyright@www.adrian.runceanu.ro
in instructiunile
SQL.
Urmatorul cod da eroare:
DECLARE
CURSOR emp_cursor IS
SELECT emp, sal
FROM em
ORDER BY SAL DESC;
v_emp_record emp_cursor%ROWTYPE;
v_count NUMBER;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_emp_record;
EXIT WHEN emp_cursor%NOTFOUND;
INSERT INTO top_paid_emps (empno, rank, sal)
VALUES (v_emp_record.empno,
emp_cursor%ROWCOUNT, v_emp_record.sal);
END LOOP;
END; … 61
Atributele cursorilor expliciti nu pot fi folosite direct in copyright@www.adrian.runceanu.ro
instructiunile SQL.
Urmatorul cod da eroare:

62
copyright@www.adrian.runceanu.ro

Întrebări?

63
Tehnici de programare cu baze de
date

#6 PL/SQL
Cursori în PL/SQL (partea II-a)

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 6

Cursori în PL/SQL
(continuare)

2
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor


2. Cursori cu parametri
3. Folosirea cursorilor pentru
actualizari
4. Folosirea cursorilor multipli

3
copyright@www.adrian.runceanu.ro

LOOP-ul FOR pentru cursor

 S-a studiat utilizarea cursorilor expliciti cu folosirea


instructiunilor DECLARE, OPEN si FETCH.
 Putem face acelasi lucru mai usor, folosind o singura
instructiune cu ajutorul LOOP-ului FOR pentru
cursor.
 Un loop FOR pentru cursor prelucreaza randuri intr-un
cursor explicit.

 Este o varianta mai rapida deoarece cursorul este


deschis, este preluat cate un rand pentru fiecare
iteratie din loop, se iese din loop dupa ce ultimul rand
a fost procesat si cursorul se inchide automat.
 Si loop-ul se incheie automat la sfarsitul iteratiei, dupa
prelucrarea ultimului rand.

4
copyright@www.adrian.runceanu.ro

Sintaxa
FOR record_name IN cursor_name
LOOP
Instructiune1;
Instructiune2;

END LOOP;
 record name – numele unei inregistrari
declarate implicit (cursor_name%ROWTYPE)
 cursor_name – identificator PL/SQL pentru un
cursor declarat anterior

5
copyright@www.adrian.runceanu.ro

Exemple:
1)

DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE deptno = 30;
BEGIN
FOR v_emp_record IN emp_cursor
LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_record.empno||' '||
v_emp_record.ename);
END LOOP;
END;
v_emp_record este o inregistrare declarata implicit.
 Putem accesa datele preluate cu aceasta inregistrare implicita
asa cum a fost exemplificat in exemplul anterior.
 Nu sunt declarate variabile pentru a pastra informatia.
 De asemenea, codul nu contine instructiunile OPEN si CLOSE.
6
copyright@www.adrian.runceanu.ro

7
copyright@www.adrian.runceanu.ro

2)
DECLARE
CURSOR dept_cursor IS
SELECT deptno, dname
FROM dept
ORDER BY deptno;
BEGIN
FOR v_dept_record IN dept_cursor
LOOP
DBMS_OUTPUT.PUT_LINE( v_dept_record.deptno
|| ' ' || v_dept_record.dname);
END LOOP;
END;

8
copyright@www.adrian.runceanu.ro

9
copyright@www.adrian.runceanu.ro

Reguli de utilizare a loop-ului FOR


pentru cursor
1. Nu se declara inregistrarea care
controleaza loop-ul deoarece este
declarata implicit
2. Domeniul de vizibilitate al inregistrarii
implicite este restrictionat in interiorul
loop-ului, deci nu putem referi
inregistrarea in afara loop-ului
3. Putem accesa datele preluate prin:
record_name.column_name

10
copyright@www.adrian.runceanu.ro

Testarea atributelor cursorului

 Se pot testa in continuare atributele de cursor, cum ar fi


%ROWCOUNT.
 Urmatorul exemplu iese din loop dupa ce au fost preluate
si prelucrate cinci randuri. Cursorul se inchide automat.

DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp;
BEGIN
FOR v_emp_record IN emp_cursor
LOOP
EXIT WHEN emp_cursor%ROWCOUNT > 5;
DBMS_OUTPUT.PUT_LINE(
v_emp_record.empno || ' ' || v_emp_record.ename);
END LOOP;
END; 11
copyright@www.adrian.runceanu.ro

12
copyright@www.adrian.runceanu.ro

Folosirea subinterogarilor in loop-ul FOR


pentru cursor

 Putem sa nu declaram cursorul deloc!


 In schimb, putem specifica direct in
loop-ul FOR instructiunea SELECT care
sta la baza cursorului.
 Avantajul consta in faptul ca toata
definitia cursorului este cuprinsa intr-o
singura instructiune FOR.
 Astfel codul poate fi ulterior modificat
mai usor si mai rapid.
13
copyright@www.adrian.runceanu.ro

Exemplu
BEGIN
FOR v_emp_record IN (SELECT empno, ename
FROM emp WHERE deptno = 30)
LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_record.empno
||' '|| v_emp_record.ename);
END LOOP;
END;

 Clauza SELECT in instructiunea FOR este practic o


subinterogare, deci trebuie inclusa intre paranteze.

14
copyright@www.adrian.runceanu.ro

15
copyright@www.adrian.runceanu.ro

 Comparati urmatoarele doua exemple. Logic sunt


identice.
 Diferenta este la modalitatea de scriere.

1)
BEGIN
FOR v_dept_rec IN (SELECT * FROM dept)
LOOP

DBMS_OUTPUT.PUT_LINE(v_dept_rec.dname);
END LOOP;
END;

16
copyright@www.adrian.runceanu.ro

2)
DECLARE
CURSOR dept_cursor IS
SELECT * FROM dept;
v_dept_rec dept_cursor%ROWTYPE;
BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO v_dept_rec;
EXIT WHEN dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_dept_rec.dname);
END LOOP;
CLOSE dept_cursor;
END;

17
copyright@www.adrian.runceanu.ro

18
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor


2. Cursori cu parametri
3. Folosirea cursorilor pentru
actualizari
4. Folosirea cursorilor multipli

19
copyright@www.adrian.runceanu.ro

2. Cursori cu parametri
 Un parametru este o variabila al carei nume este
folosit in declararea cursorului.
 Cand se deschide cursorul, valoarea parametrului
este transmisa serverului Oracle care o foloseste
pentru a decide ce randuri sa extraga in multimea
activa a cursorului.
 Aceasta inseamna ca putem inchide si deschide un
cursor explicit de cateva ori intr-un bloc sau in diferite
executii ale aceluiasi bloc, returnand de fiecare data
alta multime activa.
 Consideram un exemplu in care transmitem
cursorului orice valoare pentru region_id si acesta
returneaza numele tarilor din acea regiune.
20
copyright@www.adrian.runceanu.ro
DECLARE
CURSOR c_country (p_region_id NUMBER) IS
SELECT name, CAPITAL
FROM eba_countries
WHERE region_id = p_region_id;
v_country_record c_country%ROWTYPE;
BEGIN
OPEN c_country(50);
LOOP
FETCH c_country INTO v_country_record;
EXIT WHEN c_country%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_country_record.name ||
' ' || v_country_record.CAPITAL);
END LOOP;
CLOSE c_country;
END;

21
copyright@www.adrian.runceanu.ro

22
copyright@www.adrian.runceanu.ro

Definirea cursorilor cu parametri

 Fiecare parametru din declararea


cursorului trebuie sa aiba o valoare
corespunzatoare in instructiunea OPEN.
 Tipurile de date ale parametrilor sunt
aceleasi ca cele pentru variabilele
scalare, dar nu le precizam
dimensiunile.
 Denumirile parametrilor sunt folosite in
clauza WHERE ale instructiunii
SELECT corespunzatoare cursorului.
23
copyright@www.adrian.runceanu.ro

Sintaxa
CURSOR cursor_name
[( parameter_name datatype, ...)]
IS
select_statement;

In sintaxa:
 cursor_name este un identificator PL/SQL
pentru cursorul declarat
 parameter_name este numele parametrului
 select_statement este o instructiune
SELECT fara clauza INTO

24
copyright@www.adrian.runceanu.ro

Deschiderea cursorilor cu parametri

Sintaxa

OPEN cursor_name(parameter_value,...);

 Atunci cand se deschide un cursor


transmitem valori parametrilor.
 De aceea, putem deschide un singur
cursor explicit de mai multe ori si putem
prelua mai multe multimi active diferite.
25
copyright@www.adrian.runceanu.ro

Exemplu 1 – cursor deschis de mai multe ori

DECLARE
CURSOR c_country (p_region_id NUMBER)
IS
SELECT name, CAPITAL
FROM eba_countries
WHERE region_id = p_region_id;
v_country_record c_country%ROWTYPE;
BEGIN
OPEN c_country(50);

CLOSE c_country;
OPEN c_country (30);

26
copyright@www.adrian.runceanu.ro

Exemplu 2
DECLARE
v_deptno emp.deptno%TYPE;
CURSOR empcursor (p_deptno NUMBER) IS
SELECT empno, sal
FROM emp
WHERE deptno = p_deptno;
v_emp_rec empcursor%ROWTYPE;
BEGIN
SELECT MAX(deptno) INTO v_deptno
FROM emp;
OPEN empcursor(v_deptno);

LOOP
FETCH empcursor INTO v_emp_rec;
EXIT WHEN empcursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' ||
v_emp_rec.sal);
END LOOP;
CLOSE empcursor;
END;

27
copyright@www.adrian.runceanu.ro

28
copyright@www.adrian.runceanu.ro

Cursori cu parametri multipli

Exemplu 1- cursor cu doi parametri


DECLARE
CURSOR countrycursor2 (p_region_id NUMBER,
p_population NUMBER) IS
SELECT country_id, name, population
FROM eba_countries
WHERE region_id = p_region_id OR population >
p_population;
BEGIN
FOR v_country_record IN countrycursor2(145,10000000)
LOOP
DBMS_OUTPUT.PUT_LINE(v_country_record.country_id
||' '|| v_country_record.name||' '||
v_country_record.population);
END LOOP;
END;

29
copyright@www.adrian.runceanu.ro

Cursori cu parametri multipli


Exemplu 1- cursor cu doi parametri

30
copyright@www.adrian.runceanu.ro

Exemplu 2 – codul preia toti programatorii IT care


castiga mai mult de 1500$
DECLARE
CURSOR emp_cursor3 (p_job VARCHAR2, p_sal
NUMBER) IS
SELECT empno, ename
FROM emp
WHERE job = p_job AND sal > p_sal;
BEGIN
FOR v_emp_record IN emp_cursor3('ANALYST',
1500)
LOOP

DBMS_OUTPUT.PUT_LINE(v_emp_record.empno
||' ' || v_emp_record.ename);
END LOOP;
END; 31
copyright@www.adrian.runceanu.ro

32
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor


2. Cursori cu parametri
3. Folosirea cursorilor pentru
actualizari
4. Folosirea cursorilor multipli

33
copyright@www.adrian.runceanu.ro

3. Folosirea cursorilor pentru


actualizari
 Atunci cand sunt mai multi utilizatori conectati
in acelasi timp la baza de date, exista
posibilitatea ca un alt utilizator sa actualizeze
randurile dintr-o anumita tabela dupa ce v-ati
deschis cursorul si ati preluat randurile.
 Putem bloca randurile la deschiderea
cursorului pentru a preveni modificari facute
asupra lor de catre alti utilizatori.
 Este important sa facem acest lucru daca
vrem sa modificam aceleasi randuri noi insine

34
copyright@www.adrian.runceanu.ro

Declararea unui cursor folosind clauza FOR


UPDATE

 Atunci cand declaram un cursor FOR


UPDATE, fiecare rand este blocat cum
deschidem cursorul.

 Acest lucru previne modificarea randurilor de


catre alti utilizatori cat timp cursorul este
deschis.

 De asemenea, ni se permite noua sa


modificam randurile folosind o clauza
…WHERE CURRENT OF…
35
copyright@www.adrian.runceanu.ro

Sintaxa

CURSOR cursor_name IS
SELECT ... FROM ...
FOR UPDATE [OF column_reference
n][NOWAIT | WAIT ];

36
copyright@www.adrian.runceanu.ro

Acest lucru nu impiedica vizualizarea


randurilor de catre alti utilizatori.

 column_reference – este o coloana din


tabela ale carei randuri este necesar sa le
blocam
Daca randurile au fos deja blocate de alta
sesiune:
 NOWAIT furnizeaza o eroare imediata
serverului ORACLE
 WAIT n asteapta n secunde si returneaza o
eroare daca o alta sesiune inca blocheaza
randurile dupa cele n secunde

37
copyright@www.adrian.runceanu.ro

Cuvantul cheie NOWAIT in clauza FOR


UPDATE

 Cuvantul cheie optional NOWAIT spune


serverului ORACLE sa nu astepte daca
oricare dintre randurile solicitate sunt deja
blocate de catre alt utilizator.
 Controlul este imediat dat programului nostru
deci putem face altceva inainte de a incerca
din nou sa realizam blocarea.
 Daca omitem cuvantul cheie NOWAIT atunci
serverul ORACLE asteapta nedefinit pana
cand randurile sunt disponibile.

38
copyright@www.adrian.runceanu.ro

Exemplu

DECLARE
CURSOR emp_cursor IS
SELECT empno, ename
FROM emp
WHERE deptno = 80 FOR UPDATE
NOWAIT;

39
copyright@www.adrian.runceanu.ro

 Daca randurile sunt deja blocate de alta


sesiune si am specificat NOWAIT, atunci la
deschiderea cursorului va rezulta eroare.

 Putem incerca sa deschidem cursorul mai


tarziu.

 Se poate folosi WAIT n in loc de NOWAIT si


sa specificam numarul de secunde de
asteptare

40
copyright@www.adrian.runceanu.ro

Clauza FOR UPDATE OF


 Daca cursorul are la baza un join dintre doua
tabele poate dorim sa blocam randurile dintr-
o tabela, dar nu si din cealalta.
 Daca dorim acest lucru, specificam orice
coloana a tabelei pe care vrem sa o blocam.
DECLARE
CURSOR emp_cursor IS
SELECT e.empno, d.dname
FROM emp e, dept d
WHERE e.deptno = d. deptno AND
deptno = 80
FOR UPDATE OF salary;
… 41
copyright@www.adrian.runceanu.ro

Clauza WHERE CURRENT OF

 Clauza WHERE CURRENT OF este


folosita impreuna cu clauza FOR
UPDATE pentru a referi randul curent
(randul preluat cel mai recent) intr-un
cursor explicit.
 Clauza WHERE CURRENT OF este
folosita in instructiunile UPDATE sau
DELETE, in timp ce clauza FOR
UPDATE este specificata in declararea
cursorului.
42
copyright@www.adrian.runceanu.ro

Sintaxa
WHERE CURRENT OF cursor-name;
 cursor_name – este numele unui cursor declarat
(cursorul trebuie sa fi fost declarat cu clauza FOR
UPDATE)
 Putem folosi WHERE CURRENT OF pentru
actualizarea sau stergerea randului curent din
tabela.
 Aceasta ne permite sa aplicam actualizari si stergeri
ale randului curent fara a fi necesara folosirea
clauzei WHERE.
 Putem include clauza FOR UPDATE in interogarea
cursorului astfel incat randurile sa fie blocate la
deschidere (OPEN).
43
copyright@www.adrian.runceanu.ro

3. Folosirea cursorilor pentru


actualizari
 Cursorii se pot folosi pentru a actualiza si a
sterge randul curent.

 Se include clauza FOR UPDATE in


interogarea cursorului pentru a bloca randul
mai intai

 Se foloseste clauza WHERE CURRENT OF


pentru a referi randul curent dintr-un cursor
explicit.

44
copyright@www.adrian.runceanu.ro

Exemple

1)
UPDATE EMP
SET salary = ...
WHERE CURRENT OF emp_cursor;

45
copyright@www.adrian.runceanu.ro

Exemple
2) In acest exemplu nu avem nevoie de o coloana referinta in clauza
FOR UPDATE deoarece cursorul nu se bazeaza pe un join.

DECLARE
CURSOR empcursor IS
SELECT empno, sal FROM emp
WHERE sal <= 20000 FOR UPDATE NOWAIT;
v_emp_rec empcursor%ROWTYPE;
BEGIN
OPEN empcursor;
LOOP
FETCH empcursor INTO v_emp_rec;
EXIT WHEN empcursor%NOTFOUND;
UPDATE emp
SET sal = v_emp_rec.sal*1.1
WHERE CURRENT OF empcursor;
END LOOP;
CLOSE empcursor;
COMMIT;
END;
46
copyright@www.adrian.runceanu.ro

47
copyright@www.adrian.runceanu.ro

Exemple
3)
FOR UPDATE OF sal blocheaza numai randurile din emp nu si din
dept. Si sa nu uitam ca noi actualizam tabela, nu cursorul.

DECLARE
CURSOR ed_cursor IS
SELECT empno, sal, dname
FROM emp e, dept d
WHERE e.deptno = d.deptno
FOR UPDATE OF sal NOWAIT;
BEGIN
FOR v_ed_rec IN ed_cursor LOOP
UPDATE emp
SET sal = v_ed_rec.sal*1.1
WHERE CURRENT OF ed_cursor;
END LOOP;
COMMIT;
END;
48
copyright@www.adrian.runceanu.ro

49
copyright@www.adrian.runceanu.ro

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor


2. Cursori cu parametri
3. Folosirea cursorilor pentru
actualizari
4. Folosirea cursorilor multipli

50
copyright@www.adrian.runceanu.ro

4. Folosirea cursorilor multipli


 In programe avem adesea nevoie sa declaram si sa
folosim doi sau mai multi cursori in acelasi bloc
PL/SQL.
 Adesea acesti cursori sunt legati unii de altii prin
parametri.
1. Un exemplu de problema
Avem nevoie sa realizam un raport care listeaza
fiecare departament ca un subtitlu urmat imediat de o
lista a angajatilor din acel departament, apoi urmatorul
departament, etc.
Avem nevoie de doi cursori, cate unul pentru
fiecare din cele doua tabele.
Cursorul care are la baza tabela EMP este deschis
de cateva ori, o data pentru fiecare departament.
51
copyright@www.adrian.runceanu.ro

Solutia problemei

Pas 1
Declaram doi cursori, cate unul pentru fiecare tabela, plus
structurile de tip inregistrare asociate.

DECLARE

CURSOR c_dept IS
SELECT deptno, dname
FROM dept ORDER BY dname;

CURSOR c_emp (p_deptid NUMBER) IS


SELECT first_name, last_name
FROM EMP
WHERE deptno = p_deptid
ORDER BY last_name;
v_deptrec c_dept%ROWTYPE;
v_emprec c_emp%ROWTYPE;

De ce cursorul c_emp este declarat cu un parametru? 52


copyright@www.adrian.runceanu.ro

Pas 2
Deschidem cursorul c_dept, preluam si afisam randurile din dept
ca de obicei.

DECLARE
CURSOR c_dept IS .....;
CURSOR c_emp (p_deptid NUMBER) IS .....;
v_deptrec c_dept%ROWTYPE;
v_emprec c_emp%ROWTYPE;

BEGIN
OPEN c_dept;
LOOP
FETCH c_dept INTO v_deptrec;
EXIT WHEN c_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_deptrec.dname);
END LOOP;
CLOSE c_dept;
END;

53
copyright@www.adrian.runceanu.ro

Pas 3
 Dupa preluarea si afisarea fiecarui rand din din
tabela DEPT, avem nevoie sa preluam si sa afisam
angajatii din acel departament.
 Pentru aceasta, deschidem cursorul EMP, ii preluam
si ii afisam randurile intr-un loop imbricat si inchidem
cursorul.
 Apoi facem acelasi lucru il facem pentru urmatorul
rand din dept etc.
DECLARE
CURSOR c_dept IS .....;
CURSOR c_emp (p_deptid NUMBER) IS .....;
v_deptrec c_dept%ROWTYPE;
v_emprec c_emp%ROWTYPE;
BEGIN

54
copyright@www.adrian.runceanu.ro

OPEN c_dept;
LOOP
FETCH c_dept INTO v_deptrec;
EXIT WHEN c_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_deptrec.dname);
OPEN c_emp (v_deptrec.deptno);
LOOP
FETCH c_emp INTO v_emprec;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emprec.last_name
|| ' ' || v_emprec.first_name);
END LOOP;
CLOSE c_emp;
END LOOP;
CLOSE c_dept;
END;

55
copyright@www.adrian.runceanu.ro

2. Exemplu de problema

 Avem nevoie sa realizam un raport care


afiseaza fiecare locatie in care sunt situate
departamentele urmate de departamentele
din locatiile respective.

 Din nou, avem nevoie de doi cursori, cate


unul pentru fiecare din cele doua tabele.

 Cursorul care are la baza tabela DEPT va


deschis de cateva ori, de fiecare data pentru
fiecare locatie.
56
copyright@www.adrian.runceanu.ro
DECLARE
CURSOR c_loc IS SELECT * FROM locations;
CURSOR c_dept (p_locid NUMBER) IS
SELECT * FROM dept WHERE location_id = p_locid;
v_locrec c_loc%ROWTYPE;
v_deptrec c_dept%ROWTYPE;
BEGIN
OPEN c_loc;
LOOP
FETCH c_loc INTO v_locrec;
EXIT WHEN c_loc%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_locrec.city);
OPEN c_dept (v_locrec.location_id);
LOOP
FETCH c_dept INTO v_deptrec;
EXIT WHEN c_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_deptrec.dname);
END LOOP;
CLOSE c_dept;
END LOOP;
CLOSE c_loc;
END;

57
copyright@www.adrian.runceanu.ro

58
copyright@www.adrian.runceanu.ro

Folosirea instructiunii FOR cu cursori multipli


 Putem folosi loop-ul FOR (si alte tehnici pentru cursori cum ar fi
FOR UPDATE) cu cursori multipli ca si atunci cand folosim un
singur cursor.

DECLARE
CURSOR c_loc IS SELECT * FROM locations;
CURSOR c_dept (p_locid NUMBER) IS
SELECT * FROM dept WHERE location_id = p_locid;

BEGIN
FOR v_locrec IN c_loc
LOOP
DBMS_OUTPUT.PUT_LINE(v_locrec.city);
FOR v_deptrec IN c_dept (v_locrec.location_id)
LOOP
DBMS_OUTPUT.PUT_LINE(v_deptrec.dname);
END LOOP;
END LOOP;
END;
59
copyright@www.adrian.runceanu.ro

60
Exemplu copyright@www.adrian.runceanu.ro

Afisarea tuturor angajatilor din toate departamentele si marirea


salariilor unora dintre ei

DECLARE
CURSOR c_dept IS SELECT * FROM my_dept;
CURSOR c_emp (p_DEPT_id NUMBER) IS
SELECT * FROM my_EMP WHERE deptno = p_DEPT_id
FOR UPDATE NOWAIT;

BEGIN
FOR v_DEPTrec IN c_dept
LOOP
DBMS_OUTPUT.PUT_LINE(v_deptrec.dname);
FOR v_emprec IN c_emp (v_deptrec.deptno)
LOOP
DBMS_OUTPUT.PUT_LINE(v_emprec.last_name);
IF v_deptrec.location_id = 1700 AND v_emprec.salary < 10000
THEN UPDATE my_EMP SET salary = salary * 1.1
WHERE CURRENT OF c_emp;
END IF;
END LOOP;
END LOOP;
END;
61
copyright@www.adrian.runceanu.ro

62
copyright@www.adrian.runceanu.ro

Alte probleme
1. Sa se afiseze salariatii care au salariul mai mic de 7000$, in
urmatoarea forma:
Salariatul <nume> are salariul <salariu>
Solutie:

BEGIN
FOR v_rec IN
(SELECT ename, sal
FROM emp
WHERE sal>=7000)
LOOP
DBMS_OUTPUT.PUT_LINE ( ' Salariatul '||
v_rec.ename || ' are salariul: ' || v_rec.sal);
END LOOP;
END;
63
copyright@www.adrian.runceanu.ro

Alte probleme

2. Să se declare un cursor cu un
parametru de tipul codului
departamentului, care regăseşte
numele şi salariul angajaţilor din
departamentul respectiv, pentru care nu
s-a specificat comisionul.

Să se declare o variabilă v_nume de tipul


unei linii a cursorului.

64
copyright@www.adrian.runceanu.ro

DECLARE
CURSOR c_nume (p_idDep
emp.deptno%TYPE) IS
SELECT ename, sal*12 salariu_anual
FROM emp
WHERE comm IS NULL
AND deptno = p_idDep;

BEGIN
FOR v_rec IN c_nume (20) LOOP
DBMS_OUTPUT.PUT_LINE (' Nume:' ||
v_rec.ename || ' salariu : ' || v_rec.sal_an);
END LOOP;
END;
65
copyright@www.adrian.runceanu.ro

3. Să se dubleze valoarea salariilor celor angajaţi înainte de 1


ianuarie 1995, care nu câştigă comision.
DECLARE
CURSOR before95 IS
SELECT *
FROM emp
WHERE comm IS NULL
AND hire_date <= TO_DATE('01-JAN-1995','DD-MON-YYYY')
FOR UPDATE OF sal NOWAIT;
BEGIN
FOR x IN before95 LOOP
UPDATE emp
SET sal = sal*2
WHERE CURRENT OF before95;
END LOOP;
-- ce efect ar avea urmatoarea comanda? Explicati.
-- DBMS_OUTPUT.PUT_LINE('Au fost actualizate '||
before95%ROWCOUNT || ' linii');
COMMIT; -- se permanentizeaza actiunea si se elibereaza
blocarea
END; 66
copyright@www.adrian.runceanu.ro

Întrebări?

67
Tehnici de programare cu baze de
date

#7 PL/SQL
Excepţii în PL/SQL

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 7

Excepţii în PL/SQL

2
copyright@www.adrian.runceanu.ro

Excepţii în PL/SQL

1. Manipularea excepţiilor
2. „Prinderea în capcană” a excepţiilor
3. Prinderea excepţiilor serverului
Oracle
4. Exceptii de prindere definite de
utilizator

3
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

 Am studiat pana acum blocurile PL/SQL care


au parte declarativa si parte executabila.
 Orice cod SQL si PL/SQL care trebuie
executat se scrie intr-un bloc executabil.
 Pana acum am presupus ca, codul
functioneaza corect.
 Dar codul poate produce erori neprevazute
la un moment dat.
 O sa studiem cum sa ne descurcam cu astfel
de erori in blocurile PL/SQL.

4
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

Ce este o exceptie?
 O exceptie apare atunci cand este
descoperita o eroare in timpul executiei
unui program si care perturba functionarea
normala a programului.
Sunt multe cauze posibile ale exceptiilor:
1. Un utilizator face o greseala de ortografie
in timp ce tasteaza
2. Un program nu functioneaza corect
3. O pagina web de publicitate nu exista, etc.

5
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

 Atunci cand codul nu functioneaza


cum era de asteptat, PL/SQL produce
o exceptie.

 Atunci cand este produsa (provocata)


o exceptie, restul codului din partea
executabila a blocului PL/SQL nu se
mai executa.

6
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

Ce este un manipulator de exceptii?


 Un manipulator de exceptii este un cod care
defineste actiunile de recuperare care trebuie
executate atunci cand se produce o exceptie.
 In timpul scrierii unui cod, programatorii
trebuie sa anticipeze tipurile de erori care pot
aparea in timpul executiei codului respectiv.
 Este necesara includerea manipulatorilor de
exceptie in cod pentru a aborda aceste erori.
 Intr-un fel, manipulatorii de exceptie permit
programatorilor sa-si protejeze codul.
7
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

De ce tipuri de erori ar trebui sa tina seama


programatorii prin folosirea unor subprograme
de tratare a exceptiilor (manipulatorii de
exceptie) ?
1. Erori de sistem (de exemplu hard-diskul este
plin)
2. Erori de date (de exemplu incercarea de a
duplica valoarea unei chei primare)
3. Erori de utilizatori (de exemplu erori la
introducerea datelor de intrare)
4. Multe alte posibilitati!

8
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor
De ce este important manipulatorul de exceptii?
 Protejarea de erori a utilizatorilor (erorile frecvente
pot fi frustrante pentru utilizatori si/sau pot
determina iesirea utilizatorului din aplicatie)
 Protejarea de erori a bazei de date (datele pot fi
pierdute sau suprascrise)
 Erorile importante iau mult din resursele sistemului
(daca se face o greseala corectarea acesteia poate
fi costisitoare – utilizatorii pot solicita frecvent
serviciul de asistenta pentru erori)
 Codul este mai usor de citit deoarece rutinele
manipulatorului de eroare pot fi scrise in acelasi
bloc in care a aparut eroarea.
9
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

Manipularea exceptiilor cu PL/SQL

 Un bloc intotdeauna se incheie atunci


cand PL/SQL produce o exceptie, dar
putem specifica un manipulator de
exceptie pentru efectuarea actiunilor
finale inainte de incheierea blocului.

 Sectiunea exceptiei incepe cu cuvantul


cheie EXCEPTION.
10
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor
Exemplu:
DECLARE
v_country_name eba_countries.name%TYPE := 'Korea,
South';
v_population eba_countries.population%TYPE;
BEGIN
SELECT population INTO v_population
FROM eba_countries
WHERE name = v_country_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Country name, '||
v_country_name ||', cannot be found. Re-enter the
country name using the correct spelling.');
END;

11
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor
Executia codului propus:

12
copyright@www.adrian.runceanu.ro

1. Manipularea excepţiilor

 Atunci cand este manipulata o exceptie,


programul PL/SQL nu se incheie brusc.
 Atunci cand se produce exceptia, controlul se
transfera sectiunii exceptiei si este executat
manipulatorul de exceptie din acea sectiune.
 Blocul PL/SQL se incheie in mod obisnuit si
se finalizeaza cu succes.
 Poate aparea o singura exceptie la un
moment dat.
 Atunci cand apare o exceptie, PL/SQL
prelucreaza un singur manipulator inaintea
iesirii din bloc. 13
copyright@www.adrian.runceanu.ro

Exemple:
1)
DECLARE
v_country_name eba_countries.name%TYPE := 'Korea,
South';
v_population eba_countries.population%TYPE;
BEGIN
SELECT population INTO v_population
FROM eba_countries
WHERE name = v_country_name;
DBMS_OUTPUT.PUT_LINE(v_population); -- Punct A
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Country name, '||
v_country_name ||', cannot be found. Re-enter the country
name using the correct spelling.');
END;
Observatie:
Codul de la punctul A nu se executa deoarece
instructiunea SELECT esueaza.
14
copyright@www.adrian.runceanu.ro

2)
DECLARE
v_ename VARCHAR2(15);
BEGIN
SELECT ename INTO v_ename
FROM emp
WHERE job = 'ANALYST';
DBMS_OUTPUT.PUT_LINE('The last name
of the ANALYST is :'||v_ename);
END;
Instructiunea SELECT din bloc gaseste
ename pentru ANALYST.
Oricum, se produce o exceptie deoarece
exista mai multe date pentru ANALYST
15
copyright@www.adrian.runceanu.ro

16
copyright@www.adrian.runceanu.ro

3)
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename INTO v_ename
FROM emp
WHERE job = 'ANALYST';
DBMS_OUTPUT.PUT_LINE('The last name of the
ANALYST is :'||v_ename);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE (' Your select
statement retrieved multiple rows. Consider using a
cursor.');
END;

Acest cod contine un manipulator pentru o eroare predefinita


a serverului Oracle numita TOO_MANY_ROWS.
17
copyright@www.adrian.runceanu.ro

Eroare (exceptie)
care intrerupe
executia interogarii
18
copyright@www.adrian.runceanu.ro

Excepţii în PL/SQL

1. Manipularea excepţiilor
2. „Prinderea în capcană” a excepţiilor
3. Prinderea excepţiilor serverului
Oracle
4. Exceptii de prindere definite de
utilizator

19
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor


Putem manipula sau „prinde in capcana” orice eroare prin includerea
unui manipulator corespunzator in sectiunea de manipulare a
exceptiilor a blocului PL/SQL.
Sintaxa este:
EXCEPTION
WHEN exception1 [OR exception2. . .]
THEN
Instructiune1;
Instructiune2; …
[WHEN exception3 [OR exception4. . .]
THEN
Instructiune1;
Instructiune2; …]
[WHEN OTHERS THEN
Instructiune1;
Instructiune2; …] 20
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

 Fiecare manipulator este format dintr-o


clauza WHEN care specifica numele
unei exceptii, urmata de o secventa de
instructiuni care se executa cand se
produce exceptia.
 Putem include oricate manipulatoare in
sectiunea EXCEPTION pentru a ne
ocupa de exceptiile specifice.
 De asemenea, nu putem avea mai multi
manipulatori pentru aceeasi exceptie.
21
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

EXCEPTION
WHEN exception1 [OR exception2. . .]
THEN
Instructiune1;
Instructiune2;

[WHEN OTHERS THEN
Instructiune1;
Instructiune2;
…]

22
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

In cadrul sintaxei:

 exception – este o denumire standard a


unei exceptii predefinite sau numele unei
exceptii definite de utilizator declarata in
partea declarativa
 instructiune – reprezinta una sau mai multe
instructiuni PL/SQL sau SQL
 OTHERS – este o clauza optionala de
manipulare a exceptiilor ce preia orice
exceptie ce nu a fost manipulata explicit
23
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

Manipulatorul de exceptii OTHERS

 Sectiunea de manipulare a exceptiilor prinde


doar acele exceptii care sunt specificate.
 Orice alte exceptii nu sunt prinse pana nu
folosim manipulatorul de exceptii OTHERS.
 Manipulatorul OTHERS prinde toate
exceptiile care nu au fost deja prinse.
 Atunci cand este folosit, OTHERS trebuie sa
fie ultimul manipulator de exceptie care este
definit.
24
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

Fie urmatorul exemplu:

1. Daca programul intalneste exceptia


NO_DATA_FOUND atunci sunt executate
instructiunile din manipulatorul
corespunzator.
2. La fel se intampla si daca este intalnita
exceptia TOO_MANY_ROWS.
3. Daca sunt intalnite alte exceptii atunci sunt
executate instructiunile manipulatorului
OTHERS.
25
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

EXCEPTION
WHEN NO_DATA_FOUND THEN
Instructiune1;

WHEN TOO_MANY_ROWS THEN
Instructiune2;

WHEN OTHERS THEN
Instructiune3;
26
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

Reguli pentru prinderea exceptiilor

1. Intotdeauna adaugati manipulatoare de


exceptii atunci cand exista posibilitatea de
aparitie a unei erori.

2. Erorile apar mai ales:


a) la calcule
b) la manipularea sirurilor de caractere
c) si la operatiile asupra bazelor de date

27
copyright@www.adrian.runceanu.ro

2. „Prinderea în capcană” a excepţiilor

Reguli pentru prinderea exceptiilor

3. Folositi manipulatoare de exceptie cu


nume in locul folosirii manipulatorului
OTHERS.
4. Invatati denumirile si cauzele exceptiilor
predefinite
5. Testati codul cu diferite combinatii de date
gresite pentru a vedea potentialele erori
6. Scrieti informatiile care apar la depanare
in manipulatorul vostru de exceptie
28
copyright@www.adrian.runceanu.ro

Excepţii în PL/SQL

1. Manipularea excepţiilor
2. „Prinderea în capcană” a excepţiilor
3. Prinderea excepţiilor serverului
Oracle
4. Exceptii de prindere definite de
utilizator

29
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
 Manipularea erorilor PL/SQL este flexibila si
permite programatorilor sa foloseasca:
◦ erori definite de serverul Oracle
◦ cat si cele definite de programator
 Erorile predefinite sunt erori Oracle obisnuite
pentru care PL/SQL are denumiri de exceptii
predefinite.
 Erorile care nu sunt predefinite ne determina
sa folosim codurile de erori si mesajele ORA.
 Sintaxa este diferita pentru fiecare in parte,
dar putem prinde ambele tipuri de erori in
sectiunea EXCEPTION a blocului PL/SQL.
30
copyright@www.adrian.runceanu.ro

Tipuri de excepţii
Instructions for
Exception Description
Handling
You need not declare these
Predefined One of approximately
exceptions.
20 errors that occur
Oracle most often in
They are predefined by the Oracle
server error server and are raised implicitly
PL/SQL code
(automatically).
Non- Declare within the declarative
predefined Any other standard section and allow the Oracle
Oracle Oracle server error Server to raise them implicitly
(automatically).
server error
A condition that the
PL/SQL
User-defined Declare within the declarative
programmer
error section, and raise explicitly.
decides is
abnormal

31
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Manipularea exceptiilor cu PL/SQL

Sunt doua metode pentru a trata o exceptie:

1. Implicit de catre serverul Oracle – Are loc o


eroare Oracle si exceptia asociata se produce
imediat.
 De exemplu daca are loc eroarea ORA-
01403 cand nici un rand nu este preluat din
baza de date intr-o instructiune SELECT,
atunci PL/SQL produce exceptia
NO_DATA_FOUND 32
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
2. Explicit de catre programator –
depinde de modul de implementare a
programului.

 Se pot produce exceptii folosind


instructiunea RAISE in interiorul
blocului.

 Exceptiile produse pot fi atat definite de


utilizator cat si predefinite.
33
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Tipuri de erori ale serverului Oracle
Atunci cand au loc erori ale serverului Oracle,
automat se produce exceptia asociata, se ignora
restul sectiunii executabile a blocului si se cauta un
manipulator in sectiunea de exceptie.
Sunt doua tipuri de erori ale serverului Oracle:
1. Erori predefinite ale serverului Oracle – fiecare
dintre aceste erori are un nume predefinit
2. Erori ale serverului Oracle care nu sunt predefinite
– fiecare dintre aceste erori are un numar de eroare
standard (ORA-nnnnn) si un mesaj de eroare, dar nu
are un nume predefinit.
◦ Va puteti declara propriile nume pentru aceste erori astfel
incat puteti referi aceste erori in sectiunea de exceptie.
34
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
3.1. Capturarea erorilor predefinite ale
serverului Oracle
 Numele predefinite sunt referite in rutina de
manipulare a exceptiilor

 Exemple de exceptii predefinite:


1. NO_DATA_FOUND
2. TOO_MANY_ROWS
3. INVALID_CURSOR
4. ZERO_DIVIDE
5. DUP_VAL_ON_INDEX
35
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Exemplu1 – urmatorul exemplu foloseste eroarea
predefinita TOO_MANY_ROWS.
Observati ca nu este declarata in sectiunea DECLARATION
DECLARE
v_ename VARCHAR2(15);
BEGIN
SELECT ename INTO v_ename
FROM emp
WHERE job = 'ANALYST';
DBMS_OUTPUT.PUT_LINE('The last name of the ANALYST
is : '||v_ename);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE (' Your select statement
retrieved multiple rows. Consider using a cursor.');
END;
36
copyright@www.adrian.runceanu.ro

37
copyright@www.adrian.runceanu.ro
Exemplu2 – acest exemplu trateaza exceptiile TOO_MANY_ROWS
si NO_DATA_FOUND si are un manipulator OTHERS in cazul oricaror
altor erori.

DECLARE
v_ename VARCHAR2(15);
BEGIN
SELECT ename INTO v_ename
FROM emp
WHERE job = 'ANALYST';
DBMS_OUTPUT.PUT_LINE('The last name of the ANALYST is :
'||v_ename);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE ('Select statement found multiple
rows');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Select statement found no rows');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Another type of error occurred');
END;

38
copyright@www.adrian.runceanu.ro

39
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
3.2. Capturarea erorilor nepredefinite ale
serverului Oracle

 Exceptiile nepredefinite sunt asemanatoare


cu cele predefinite, totusi ele nu au nume
predefinite in PL/SQL.
 Sunt erori standard ale serverului Oracle si
au numere de eroare ORA.
 Va creati propriile nume pentru ele in
sectiunea DECLARE si asociati aceste nume
cu numerele de eroare ORA folosind functia
PRAGMA EXCEPTION_INIT.
40
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
3.2. Capturarea erorilor nepredefinite ale
serverului Oracle (continuare)
 Puteti captura o eroare a serverului Oracle
care nu este predefinita declarand-o mai
intai.
 Exceptia declarata se produce implicit.
 In PL/SQL PRAGMA EXCEPTION_INIT
spune compilatorului sa asocieze un nume
de exceptie cu un numar de eroare Oracle.
 Va permite sa referiti orice exceptie a
serverului Oracle prin nume si sa scrieti un
manipulator specific pentru ea.
41
copyright@www.adrian.runceanu.ro

Tipuri de excepţii
Instructions for
Exception Description
Handling
You need not declare these
Predefined One of approximately
exceptions.
20 errors that occur
Oracle most often in
They are predefined by the Oracle
server error server and are raised implicitly
PL/SQL code
(automatically).
Non- Declare within the declarative
predefined Any other standard section and allow the Oracle
Oracle Oracle server error Server to raise them implicitly
(automatically).
server error
A condition that the
PL/SQL
User-defined Declare within the declarative
programmer
error section, and raise explicitly.
decides is
abnormal

42
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Erori care nu sunt predefinite
Examinati urmatorul exemplu:

BEGIN
INSERT INTO dept (deptno, dname)
VALUES (80, NULL);
END;

Se va afisa:
ORA-01400: cannot insert NULL into
(“LUCRU”. “DEPT”.“DNAME”)
43
copyright@www.adrian.runceanu.ro

44
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
 Instructiunea INSERT incearca sa insereze
valoarea NULL pentru coloana
department_name a tabelei departments.
 Totusi, operatia nu are succes deoarece
department_name este o coloana NOT
NULL.
 Nu este nici un nume de eroare predefinita
pentru incalcarea unei constrangeri NOT
NULL.
 Modul de rezolvare a acestei probleme este
de a declara propriul nume si a-l asocia cu
eroarea ORA-01400. 45
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Pasii necesari:

1. Declararea numelui exceptiei in sectiunea


declarativa

2. Asocierea exceptiei declarate cu numarul


erorii standard a serverului Oracle folosind
functia PRAGMA EXCEPTION_INIT

3. Referirea numelui exceptiei declarate in


cadrul rutinei corespunzatoare
manipulatorului 46
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Exemplu:
DECLARE
e_insert_excep EXCEPTION;
PRAGMA EXCEPTION_INIT (e_insert_excep, -
01400);
BEGIN
INSERT INTO dept (deptno, dname)
VALUES (66, NULL);
EXCEPTION
WHEN e_insert_excep THEN
DBMS_OUTPUT.PUT_LINE('INSERT FAILED');
END;

47
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Executia codului propus:

48
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
Functii pentru capturarea exceptiilor
 Atunci cand are loc o exceptie, puteti regasi
codul erorii asociate sau un mesaj de eroare
prin folosirea a doua functii:
1. SQLERRM – returneaza un sir de caractere
ce contine mesajul asociat cu numarul erorii
2. SQLCODE – returneaza valoarea numerica
pentru codul erorii (O puteti atribui unei
variabile de tip NUMBER)
Pe baza valorilor codului sau pe baza
mesajului, puteti decide masurile ulterioare ce
trebuie luate. 49
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
SQLCODE Value Description
0 No exception encountered

1 User defined exception

+100 NO_DATA_FOUND exception

Negative number Another Oracle Server error number

 Functiile SQLCODE si SQLERRM nu pot fi


folosite direct intr-o instructiune SQL.
 In schimb, trebuie sa atribuiti valorile lor unor
variabile locale, apoi folositi acele variabile in
instructiuni SQL asa cum va arata urmatorul
exemplu: 50
copyright@www.adrian.runceanu.ro

3. Prinderea excepţiilor serverului


Oracle
DECLARE
v_error_code NUMBER;
v_error_message VARCHAR2(255);
BEGIN

EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
v_error_code := SQLCODE ;
v_error_message := SQLERRM ;
INSERT INTO error_log(e_user, e_date, error_code,
error_message)
VALUES(USER, SYSDATE, v_error_code,
v_error_message);
51
END;
copyright@www.adrian.runceanu.ro

Excepţii în PL/SQL

1. Manipularea excepţiilor
2. „Prinderea în capcană” a excepţiilor
3. Prinderea excepţiilor serverului
Oracle
4. Excepţii de prindere definite de
utilizator

52
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
 Aceste erori nu sunt gasite automat de catre
serverul Oracle, dar sunt definite de
programator si sunt specifice codului
programatorului.

 Un exemplu de eroare definita de


programator este INVALID_MANAGER_ID.

 Puteti defini atat un cod de eroare cat si un


mesaj de eroare pentru erorile definite de
utilizator.
53
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator

Instructions for
Exception Description
Handling
You need not declare
One of approximately
these exceptions.
Predefined Oracle 20 errors that occur
They are predefined by
server error most often in
the Oracle server and
PL/SQL code
are raised implicitly.
Declare within the
Non-predefined declarative section
Any other standard
Oracle server Oracle server error
and allow the Oracle
error server to raise them
implicitly.
A condition that the
Declare within the
developer
User-defined error determines is
declarative section,
and raise explicitly.
abnormal

54
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator

 PL/SQL ne permite sa definim propriile


exceptii in functie de cerintele aplicatiei.

 De exemplu puteti dori sa creati o exceptie


definita de utilizator atunci cand este nevoie
sa abordati conditii de eroare pentru datele
de intrare.

55
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
De exemplu, sa presupunem ca
programul solicita utilizatorului un numar si
nume de departament astfel incat sa poata
actualiza numele departamentului.
DECLARE
v_name VARCHAR2(20):='IT_PROG';
v_deptno NUMBER := 27;
BEGIN
UPDATE dept
SET dname = v_name
WHERE deptno = v_deptno;
END; 56
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
Executia codului propus:

57
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
Executia codului propus:

58
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator

 Ce se intampla atunci cand utilizatorul


introduce un department incorect?

 Codul de mai sus nu produce o eroare


Oracle.

 Este nevoie sa definim o eroare utilizator.

 Acest lucru se face prin:

59
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
1. Declararea numelui exceptiei definite de
utilizator in sectiunea declarativa

e_invalid_department EXCEPTION;

2. Folosirea instructiunii RAISE pentru a


produce explicit exceptia in sectiunea
executabila.

IF SQL%NOTFOUND THEN RAISE


e_invalid_department;
60
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
3. Referirea exceptiei declarate in
rutina manipulatorului de exceptie
corespunzator

EXCEPTION WHEN
e_invalid_department THEN
DBMS_OUTPUT.PUT_LINE('No such
department id.');

61
Codul complet copyright@www.adrian.runceanu.ro

DECLARE
e_invalid_department EXCEPTION;
v_name VARCHAR2(20):='Accounting';
v_deptno NUMBER := 27;
BEGIN
UPDATE dept
SET dname = v_name
WHERE deptno = v_deptno;
IF SQL%NOTFOUND THEN
RAISE e_invalid_department;
END IF;
COMMIT;
EXCEPTION
WHEN e_invalid_department
THEN DBMS_OUTPUT.PUT_LINE('No
such department no');
ROLLBACK;
62
END;
copyright@www.adrian.runceanu.ro

63
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
Instructiunea RAISE
Se poate folosi instructiunea RAISE pentru a ridica o
exceptie denumita. Putem ridica:

1. O exceptie proprie (care este o exceptie definita


de utilizator)
Exceptie
IF v_grand_total=0 THEN proprie
RAISE e_invalid_total;
ELSE
DBMS_OUTPUT.PUT_LINE(v_num_students/v_gr
and_total);
END IF;
64
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator

2. O eroare a serverului Oracle


Eroare a
IF v_grand_total=0 THEN serverului Oracle
RAISE ZERO_DIVIDE;
ELSE
DBMS_OUTPUT.PUT_LINE(v_num_students/v_gr
and_total);
END IF;

65
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
Procedura RAISE_APPLICATION_ERROR
 Puteti folosi procedura
RAISE_APPLICATION_ERROR pentru a
returna mesaje de eroare definite de utilizator
din subprogramele stocate.
 Principalul avantaj al folosirii acestei proceduri
in locul instructiunii RAISE este faptul ca
procedura permite sa asociati exceptiei propriul
numar de eroare si mesajul semnificativ.
 Numerele de eroare trebuie sa se regaseasca
in intervalul [-20999,-20000].
66
copyright@www.adrian.runceanu.ro

Sintaxa
RAISE_APPLICATION_ERROR
error_number,(message[, {TRUE |
FALSE}]);

 error_number – este un numar specificat de


utilizator pentru exceptie
 message – este un mesaj specificat de
utilizator pentru exceptie. Este un sir de
caractere lung pana la 2048 bytes.

67
copyright@www.adrian.runceanu.ro

 TRUE / FALSE – este un parametru de tip


boolean optional (daca este TRUE atunci
eroarea este plasata pe stiva erorilor
anterioare, daca este FALSE, iar aceasta este
valoarea implicita, eroarea inlocuieste toate
erorile anterioare)

 Domeniul de valori [-20999,-20000] este


rezervat de Oracle pentru folosirea lor de catre
programator si nu este niciodata folosit pentru
erorile predefinite ale serverului Oracle.

68
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator

Procedura RAISE_APPLICATION_ERROR se
poate folosi in doua locuri diferite:

1. Sectiunea executabila

2. Sectiunea pentru exceptii

69
copyright@www.adrian.runceanu.ro

4. Excepţii de prindere definite de


utilizator
Exemplu - Procedura RAISE_APPLICATION_ERROR in
sectiunea executabila

Atunci cand este apelata, procedura afiseaza utilizatorului


numarul de eroare si mesajul.
DECLARE
v_mgr PLS_INTEGER := 123;
BEGIN
DELETE FROM emp
WHERE mgr = v_mgr;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20202,'This is not a
valid manager');
END IF;
END;
70
copyright@www.adrian.runceanu.ro

71
copyright@www.adrian.runceanu.ro
Exemplu - RAISE_APPLICATION_ERROR in sectiunea pentru
exceptii

DECLARE
v_mgr PLS_INTEGER := 27;
v_employee_no emp.empno%TYPE;
BEGIN
SELECT empno INTO v_employee_no
FROM emp
WHERE mgr = v_mgr;
DBMS_OUTPUT.PUT_LINE('The employee who works for
manager_id '||v_mgr||' is: '||v_employee_no);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR (-20201,'This manager has
no employees');
WHEN TOO_MANY_ROWS THEN
RAISE_APPLICATION_ERROR (-20202,'Too many
employees were found.');
END;
72
copyright@www.adrian.runceanu.ro

73
copyright@www.adrian.runceanu.ro

Exemplu - RAISE_APPLICATION_ERROR cu o exceptie definita de


utilizator

DECLARE
e_name EXCEPTION;
PRAGMA EXCEPTION_INIT (e_name, -20999);
v_last_name emp.ename%TYPE := 'Silly Name';
BEGIN
DELETE FROM emp WHERE ename = v_last_name;
IF SQL%ROWCOUNT =0 THEN RAISE_APPLICATION_ERROR(-
20999,'Invalid last name');
ELSE DBMS_OUTPUT.PUT_LINE(v_last_name||' deleted');
END IF;
EXCEPTION WHEN e_name THEN DBMS_OUTPUT.PUT_LINE
('Valid last names are: ');
FOR c1 IN (SELECT DISTINCT ename FROM emp)
LOOP
DBMS_OUTPUT.PUT_LINE(c1.ename);
END LOOP;
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error deleting
from employees');
END;
74
copyright@www.adrian.runceanu.ro

75
copyright@www.adrian.runceanu.ro

Întrebări?

76
Tehnici de programare cu baze de
date

#8 PL/SQL
Proceduri în PL/SQL

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 8

Proceduri în PL/SQL

2
copyright@www.adrian.runceanu.ro

Cuprins
Proceduri in PL/SQL

1. Exceptii. Domeniul variabilelor -


recapitulare
2. Proceduri şi funcţii
3. Folosirea parametrilor în proceduri

3
copyright@www.adrian.runceanu.ro

RECAPITULARE

 O exceptie denumita este un fel de


variabila PL/SQL.
 Pentru manipularea corecta a exceptiilor
trebuie sa intelegeti:
◦ domeniul
◦ si vizibilitatea variabilelor exceptiilor
 Acest lucru este deosebit de important in
cazul blocurilor imbricate.

4
copyright@www.adrian.runceanu.ro

 Blocuri imbricate – exista un bloc exterior si


un bloc interior.
 Blocurile pot fi imbricate pe oricate nivele, nu
exista nici o restrictie in acest sens.

5
copyright@www.adrian.runceanu.ro
Exemplu:
Un bloc exterior – parinte (reprezentat in albastru) si un
bloc interior – copil (reprezentat in rosu).
Variabila v_outer_variable este declarata in blocul
exterior si variabila v_inner_variable este declarata in blocul
interior.

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;
6
copyright@www.adrian.runceanu.ro

7
copyright@www.adrian.runceanu.ro
Domeniul de aplicare a unei variabile este blocul sau blocurile in care variabila
este accesibila.
In PL/SQL domeniul unei variabile este blocul in care este declarata si in
toate blocurile imbricate in interiorul blocului declarativ.
Care este domeniul celor doua variabile declarate in exemplul anterior?
Fie urmatorul exemplu:
DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='11/30/1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
BEGIN
DBMS_OUTPUT.PUT_LINE('Father''s Name: ' ||
v_father_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth: ' ||
v_date_of_birth);
DBMS_OUTPUT.PUT_LINE('Child''s Name: ' ||
v_child_name);
END;
DBMS_OUTPUT.PUT_LINE('Date of Birth: ' ||
v_date_of_birth); 8
copyright@www.adrian.runceanu.ro

9
copyright@www.adrian.runceanu.ro

De ce urmatorul cod nu va functiona corect?

BEGIN
DECLARE
CURSOR emp_curs IS SELECT * FROM emp;
v_emp_rec emp_curs%ROWTYPE;
BEGIN
OPEN emp_curs;
LOOP
FETCH emp_curs INTO v_emp_rec;
EXIT WHEN emp_curs%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_emp_rec.ename);
END LOOP;
END;
CLOSE emp_curs;
END;
10
copyright@www.adrian.runceanu.ro

Cursorul este vizibil doar in


blocul unde a fost definit

11
copyright@www.adrian.runceanu.ro

Urmatorul cod va functiona corect? Justificati.

DECLARE
CURSOR emp_curs IS SELECT * FROM emp;
BEGIN
OPEN emp_curs;
DECLARE
v_emp_rec emp_curs%ROWTYPE;
BEGIN
LOOP
FETCH emp_curs INTO v_emp_rec;
EXIT WHEN emp_curs%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_rec.ename);
END LOOP;
END;
CLOSE emp_curs;
END;

12
copyright@www.adrian.runceanu.ro

13
copyright@www.adrian.runceanu.ro

Cum rezolva PL/SQL denumirile de variabile – recapitulare

Atunci cand referiti numele unei variabile intr-un bloc, PL/SQL


cauta mai intai sa vada daca o variabila cu acel nume a fost declarata
in blocul respectiv (variabila locala).
Daca nu o gaseste, PL/SQL cauta in blocul exterior etc.

DECLARE -- outer block


v_outervar VARCHAR2(20);
BEGIN
DECLARE -- middle-level block
v_middlevar VARCHAR2(20);
BEGIN
BEGIN -- innermost block
v_outervar := 'Joachim';
v_middlevar := 'Chang';
END;
END;
END;
14
copyright@www.adrian.runceanu.ro

Manipularea exceptiilor in blocurile imbricate

Puteti trata exceptia prin:

 Manipularea ei in blocul in care apare

 Propagarea ei in mediul apelant (care poate


fi un bloc de un nivel superior)

15
copyright@www.adrian.runceanu.ro

Propagarea exceptiilor catre blocul exterior


 Daca se produce o exceptie in sectiunea
executabila a blocului interior si nu este nici un
manipulator de exceptie corespunzator, blocul
PL/SQL se incheie cu esec si exceptia este
propagata in blocul exterior.
 In urmatorul exemplu apare o exceptie in timpul
executiei blocului interior.
 Sectiunea de exceptie a blocului interior nu
reuseste sa trateze exceptia.
 Blocul interior se incheie fara succes si PL/SQL
propaga exceptia catre blocul exterior.
 Sectiunea de exceptie a blocului exterior
manipuleaza cu success exceptia.
16
copyright@www.adrian.runceanu.ro

DECLARE -- outer block


e_no_rows EXCEPTION;
BEGIN
BEGIN -- inner block
IF ...THEN RAISE e_no_rows; -- exception
occurs here

END;
… -- Remaining code in outer block’s
executable
… -- section is skipped
EXCEPTION
WHEN e_no_rows THEN -- outer block handles
the exception

END;
17
copyright@www.adrian.runceanu.ro

 Daca PL/SQL produce o exceptie si blocul curent


nu are un manipulator pentru acea exceptie, acea
exceptie se propaga succesiv blocurilor exterioare
pana cand este gasit un manipulator.
 Atunci cand exceptia se propaga catre blocul
exterior, operatiile executabile ramase sunt
ignorate, nu se mai executa.
 Un avantaj al acestui lucru este ca puteti sa
adaugati instructiuni care necesita propriile
manipulari de erori in propriile blocuri, in timp ce
pastram manipularile exceptiilor mai generale (de
exemplu WHEN OTHERS) pentru blocul apelant.

18
copyright@www.adrian.runceanu.ro

Exemplu – propagarea exceptiilor predefinite dintr-un sub-bloc


DECLARE
v_last_name emp.ename%TYPE;
BEGIN
BEGIN
SELECT ename INTO v_last_name
FROM emp
WHERE empno = 999;
DBMS_OUTPUT.PUT_LINE('Message 1');
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Message 2');
END;
DBMS_OUTPUT.PUT_LINE('Message 3');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Message 4');
END;
Employee_id 999 nu exista. Ce se afiseaza atunci cand este executat
codul anterior?
19
copyright@www.adrian.runceanu.ro

20
copyright@www.adrian.runceanu.ro

Domeniul de aplicare al numelor de exceptii


 Exceptiile predefinite ale serverului Oracle cum ar
fi NO_DATA_FOUND, TOO_MANY_ROWS si
OTHERS nu sunt declarate de catre programator.
Pot fi produse in orice bloc si manipulate in orice
bloc.
 Exceptiile denumite de utilizator sunt declarate de
programator ca variabile de tipul EXCEPTION. Ele
respecta aceleasi reguli ca si celelalte variabile.
 Prin urmare, o exceptie definita de utilizator
declarata intr-un bloc interior nu poate fi referita in
sectiunea de exceptie a unui bloc exterior.

21
copyright@www.adrian.runceanu.ro

Cuprins

1. Exceptii. Domeniul variabilelor -


recapitulare
2. Proceduri şi funcţii
3. Folosirea parametrilor în proceduri

22
copyright@www.adrian.runceanu.ro

2. Proceduri
Crearea procedurilor

 Am studiat cum sa scriem si sa executam blocuri


PL/SQL anonime.
 Blocurile anonime sunt scrise ca parte a
programului aplicatie.
 Acum vom studia cum sa creem, sa executam si
sa administram subprogramele PL/SQL.
 Acestea sunt stocate in baza de date, oferind
multe beneficii cum ar fi o mai buna securitate si
rapiditate.

23
copyright@www.adrian.runceanu.ro

2. Proceduri

Sunt doua tipuri de subprograme PL/SQL:

1. Proceduri

2. Functii

24
copyright@www.adrian.runceanu.ro

Diferenta dintre blocuri anonime si


subprograme

 Blocurile anonime – sunt blocuri executabile


PL/SQL fara nume.

 Deoarece sunt nedenumite, ele nu pot fi nici


reutilizate sau stocate in baza de date pentru o
folosire ulterioara.

25
Diferenta dintre blocuri anonime si subprograme
copyright@www.adrian.runceanu.ro

 Subprogramele – procedurile si functiile sunt


blocuri PL/SQL denumite.
 Sunt cunoscute sub denumirea de subprograme.
 Aceste subprograme sunt compilate si stocate in baza
de date.
 Structura blocului unui subprogram este
asemanatoare cu structura unui bloc anonim.
 In timp ce subprogramele pot fi partajate in mod
explicit, implicit este de a le face private schemei
proprii.
Mai tarziu subprogramele devin blocuri in constructia
pachetelor si triggerelor (declansatorilor).

26
copyright@www.adrian.runceanu.ro

Anonymous Blocks

DECLARE (Optional)
Variables, cursors, etc.;
BEGIN (Mandatory)
SQL and PL/SQL statements;
EXCEPTION (Optional)
WHEN exception-handling actions;
END; (Mandatory)

27
copyright@www.adrian.runceanu.ro

Subprograms (Procedures)

CREATE [OR REPLACE]


PROCEDURE name [parameters]
IS|AS (Mandatory)
Variables, cursors, etc.; (Optional)
BEGIN (Mandatory)
SQL and PL/SQL statements;
EXCEPTION (Optional)
WHEN exception-handling actions;
END [name]; (Mandatory)
28
copyright@www.adrian.runceanu.ro

Blocuri anonime si subprograme


Anonymous Blocks Subprograms
(blocuri anonime) (Suprograme)
Blocuri PL/SQL fara nume Blocuri PL/SQL cu nume
Se compileaza la fiecare Se compileaza o data, numai la
executie creare
Nu se stocheaza in baza de
Se stocheaza in baza de date
date
Nu pot fi utilizate(folosite) de Au nume si de aceea pot fi
catre alte aplicatii utilizate de catre alte aplicatii
Subprogramele numite functii
Nu returneaza valori
trebuie sa returneze valori
Nu pot avea parametri Pot avea parametri
29
copyright@www.adrian.runceanu.ro

Avantajele folosirii subprogramelor


Procedurile si functiile au multe avantaje ca urmare
a modularizarii codului:

1. Intretinere usoara:
 Modificarile este suficient sa se faca o data pentru
a imbunatati mai multe aplicatii si pentru a
minimiza testele

2. Reutilizarea codului:
 Subprogramele sunt puse intr-un singur loc.
 Odata compilate si validate, pot utilizate si
reutilizate in oricate aplicatii.
30
copyright@www.adrian.runceanu.ro

Avantajele folosirii subprogramelor

3. Imbunatateste securitatea datelor:


 Accesul indirect la obiectele bazei de date este
permis de acordarea privilegiilor de securitate
asupra subprogramelor.
 Implicit, subprogramele functioneaza cu privilegiile
proprietarului, nu cu cele ale utilizatorului.

4. Integritatea datelor:
 Actiunile pot fi grupate intr-un bloc si sunt
executate impreuna sau deloc.

31
copyright@www.adrian.runceanu.ro

Avantajele folosirii subprogramelor


5. Imbunatatirea performantelor:
 Puteti refolosi codul PL/SQL compilat, care este
stocat in zona cache SQL de partajare.
 Subsecventele care apeleaza subprogramul evita
recompilarea codului.
 De asemenea, multi utilizatori pot imparti o
singura copie a codului unui subprogram din
memorie.
6. Imbunatatirea claritatii codului:
 Prin utilizarea unor nume si conventii adecvate
pentru a descrie actiunea subprogramului, puteti
reduce necesarul de comentarii si spori claritatea
codului. 32
copyright@www.adrian.runceanu.ro

In concluzie, procedurile si functiile:

 Sunt blocuri PL/SQL denumite


 Sunt numite subprograme PL/SQL
 Au structuri de bloc asemanatoare
blocurilor anonime:
◦ Parametri optionali
◦ Sectiune declarativa optionala (dar cuvantul
cheie DECLARE se schimba in IS sau AS)
◦ Sectiune executabila obligatorie
◦ Sectiune optionala de manipulare a exceptiilor

33
copyright@www.adrian.runceanu.ro

Proceduri
 O procedura este un bloc PL/SQL cu nume care poate
accepta parametri
 In general, puteti folosi o procedura pentru a realiza
o actiune (uneori numita „efect secundar”)
 O procedura este compilata si stocata in baza de
date ca un obiect din schema
◦ Este prezentata in USER_OBJECTS ca un obiect
de tip PROCEDURE
◦ Mai multe detalii sunt prezentate in
USER_PROCEDURES
◦ Codul PL/SQL detaliat este in USER_SOURCE

34
copyright@www.adrian.runceanu.ro

Sintaxa pentru crearea procedurilor

CREATE [OR REPLACE]


PROCEDURE procedure_name
[(parameter1 [mode1] datatype1,
parameter2 [mode2] datatype2, . . .)]
IS|AS

procedure_body;

35
copyright@www.adrian.runceanu.ro

 Parametrii sunt optionali


 Modul implicit este IN
 Tipul de date poate fi atat explicit (de exemplu
VARCHAR2) cat si implicit cu %TYPE
 Corpul de instructiuni este asemanator cu cel al
unui bloc anonim.
 Folositi CREATE PROCEDURE urmat de nume,
parametrii optionali si unul din cuvintele cheie IS
sau AS
 Adaugati optiunea OR REPLACE pentru a
suprascrie o procedura existenta
 Scrieti un bloc PL/SQL care contine variabile
locale, un BEGIN si un END (sau END
procedure_name)
36
copyright@www.adrian.runceanu.ro

Sintaxa pentru crearea procedurilor

CREATE [OR REPLACE]


PROCEDURE procedure_name
[(parameter1 [mode] datatype1,
parameter2 [mode] datatype2, ...)]
IS|AS
[local_variable_declarations; …]
BEGIN

END [procedure_name];

37
copyright@www.adrian.runceanu.ro

Exemplu
In urmatorul exemplu, procedura add_dept
insereaza un departament nou care are deptno
= 80 si dname = ST-Curriculum.
Procedura declara in sectiunea declarativa doua
variabile v_dept_id si v_dept_name.

CREATE OR REPLACE PROCEDURE


add_dept IS
v_dept_id dept.deptno%TYPE;
v_dept_name dept.dname%TYPE;

38
copyright@www.adrian.runceanu.ro

BEGIN
add_dept;
v_dept_id :=80;
v_dept_name :='ST-Curriculum';
INSERT INTO dept(deptno,dname)
VALUES(v_dept_id,v_dept_name);
DBMS_OUTPUT.PUT_LINE('Inserted
'||SQL%ROWCOUNT ||'row');
END;
Partea declarativa a procedurii incepe imediat dupa
declararea procedurii si nu incepe cu cuvantul cheie
DECLARE.
Aceasta procedura foloseste atributul de cursor
SQL%ROWCOUNT pentru a verifica daca randul a fost
inserat cu succes.
SQL%ROWCOUNT returneaza 1 in acest caz.

39
copyright@www.adrian.runceanu.ro

40
copyright@www.adrian.runceanu.ro

Proceduri care se apeleaza

O procedura se poate apela din:


1. Un bloc anonim
2. Alta procedura
3. O aplicatie apelanta

Observatie:
Nu puteti apela o procedura din
interiorul unei instructiuni SQL cum ar fi
SELECT.
41
copyright@www.adrian.runceanu.ro

Pentru a executa o procedura in Oracle


Application Express, scrieti si rulati un mic bloc
anonim care apeleaza procedura.
Exemplu:
CREATE OR REPLACE PROCEDURE
add_dept IS ...
BEGIN
add_dept;
SELECT deptno, dname
FROM dept
WHERE deptno=80;
END;
Instructiunea SELECT din final confirma faptul
ca randul a fost inserat cu succes.
42
copyright@www.adrian.runceanu.ro

Corectarea erorilor in instructiunile CREATE


PROCEDURE

 Daca sunt erori de compilare, Application


Express le afiseaza in partea de afisare a ferestrei
de comenzi PL/SQL.

 Trebuie sa editam codul sursa pentru a corecta


erorile.

 Procedura este inca creata chiar daca contine


erori.

43
copyright@www.adrian.runceanu.ro

Corectarea erorilor in instructiunile CREATE


PROCEDURE

Dupa ce am corectat erorile, este necesar sa


recream procedura.
Sunt doua modalitati de a face acest lucru:

1. Folosirea unei instructiuni CREATE or


REPLACE PROCEDURE pentru a rescrie codul
existent (metoda cea mai folosita)
2. Eliminarea procedurii mai intai (DROP) si apoi
executarea instructiunii CREATE PROCEDURE
(mai putin folosita)

44
copyright@www.adrian.runceanu.ro
 Dupa ce procedura a fost creata cu succes,
definitia ei ar trebui salvata daca doriti sa-i
modificati codul ulterior.

45
copyright@www.adrian.runceanu.ro

In Application Express in fereastra de comenzi SQL faceti


click pe SAVE si introduceti un nume si o descriere
optionala pentru codul vostru.

46
copyright@www.adrian.runceanu.ro

Puteti vizualiza si reincarca codul ulterior facand click


pe butonul Saved SQL in fereastra de comenzi SQL.

47
copyright@www.adrian.runceanu.ro

Cuprins

1. Determinarea domeniului
variabilelor - recapitulare
2. Proceduri şi funcţii
3. Folosirea parametrilor în proceduri

48
copyright@www.adrian.runceanu.ro

Folosirea parametrilor in proceduri

 Pentru a face procedurile mai flexibile, este


important sa oferim date variate
procedurii prin intermediul parametrilor
de intrare.

 Rezultatele calculate pot fi returnate prin


folosirea parametrilor OUT sau IN OUT.

49
copyright@www.adrian.runceanu.ro

Folosirea parametrilor in proceduri


Ce sunt parametrii?

 Parametrii transmit si comunica date intre


programul apelant si subprogram.

 Parametri sunt variabile speciale ale caror valori


de intrare sunt initializate de mediul apelant
atunci cand subprogramul este apelat, iar
rezultatele sunt returnate mediului apelant.

50
copyright@www.adrian.runceanu.ro

Folosirea parametrilor in proceduri


Ce sunt parametrii?
 Prin conventie, parametrii sunt numiti adesea cu
prefixul „p_”.
 Parametri sunt referiti de obicei ca argumente.
 In orice caz, argumentele sunt mult mai adecvate
ca valori reale atribuite variabilelor parametri
atunci cand subprogramul este apelat.
 Chiar daca parametrii sunt un fel de variabile,
parametrii de tip IN se comporta ca si constante si nu
pot fi schimbati de subprogram.

51
copyright@www.adrian.runceanu.ro

Crearea procedurilor cu parametri


Urmatorul exemplu prezinta o procedura cu 2
parametri.
Se creeaza procedura raise_salary in baza de date.
Apoi se executa procedura transmitandu-i valorile 176 si
10 pentru cei doi parametri.
CREATE OR REPLACE PROCEDURE raise_salary
(p_id IN emp.empno%TYPE, p_percent IN
NUMBER)
IS
BEGIN
UPDATE emp
SET sal = sal * (1 + p_percent/100)
WHERE empno = p_id;
END raise_salary;

BEGIN raise_salary(7369,10); END;


52
copyright@www.adrian.runceanu.ro

Crearea procedurilor cu parametri

53
copyright@www.adrian.runceanu.ro

Crearea procedurilor cu parametri

54
copyright@www.adrian.runceanu.ro

Apelarea procedurilor cu parametri


 Se foloseste numele procedurii si valorile
parametrilor ca in exemplul anterior.

 Argumentele trebuie sa fie in aceeasi ordine in


care sunt declarate in procedura.

 Pentru ca o procedura sa fie apelata de catre alta


procedura, se foloseste un apel direct in partea
executabila a blocului.

55
copyright@www.adrian.runceanu.ro

Exemplu
CREATE OR REPLACE PROCEDURE
process_employees
IS
CURSOR emp_cursor IS
SELECT empno
FROM my_employees;
BEGIN
FOR v_emp_rec IN emp_cursor
LOOP
raise_salary(v_emp_rec.empno, 10);
END LOOP;
COMMIT;
END process_employees;
56
copyright@www.adrian.runceanu.ro

Exemplu

57
copyright@www.adrian.runceanu.ro

Exemplu

58
copyright@www.adrian.runceanu.ro

Tipuri de parametri

 Sunt doua tipuri de parametri:


1. formali
2. actuali

 Un parametru cu nume declarat in antetul


procedurii este numit parametru formal.

 Parametrul corespunzator de la apel se


numeste parametru actual.
59
copyright@www.adrian.runceanu.ro

Tipuri de parametri
In urmatorul exemplu puteti spune ce
parametru este formal si ce parametru este
actual?
CREATE OR REPLACE PROCEDURE
fetch_emp
(p_emp_id IN employees.empno%TYPE)
IS ...
END;
/* Acum se face apelul procedurii dintr-un bloc
anonim */
BEGIN fetch_emp(v_emp_id); END;

60
copyright@www.adrian.runceanu.ro

Parametrii formali

Parametrii formali sunt variabile care sunt declarate in


lista de parametri a specificatiei subprogramului.

61
copyright@www.adrian.runceanu.ro

Parametrii formali
In urmatorul exemplu, in procedura raise_sal,
identificatorii p_id si p_sal reprezinta parametri
formali.
CREATE PROCEDURE raise_sal (p_id IN
NUMBER, p_sal IN NUMBER) IS
BEGIN…
END raise_sal;
Observati ca tipurile de date ale parametrilor
formali nu au dimensiuni.
De exemplu, p_sal este de tip NUMBER si nu
NUMBER(6,2).
62
copyright@www.adrian.runceanu.ro

Parametrii actuali

Parametrii actuali pot fi:


 literali,
 variabile
 sau expresii care apar in lista de parametri a unui
subprogram apelat.

63
copyright@www.adrian.runceanu.ro

Parametrii actuali
In urmatorul exemplu se apeleaza raise_sal unde
variabila a_emp_id este parametrul actual
pentru parametrul formal p_id.
a_emp_id := 100;
raise_sal(a_emp_id, 2000);

Parametrii actuali:
Sunt asociati cu parametrii formali cand se
apeleaza subprogramul
Pot fi expresii – de exemplu:
raise_sal(a_emp_id, v_raise+100);
64
copyright@www.adrian.runceanu.ro

Tipuri de parametri

 Parametrii formali si parametrii actuali trebuie sa fie


de tipuri de date compatibile.

 Daca este necesar, inainte de atribuirea de valori,


PL/SQL converteste tipul de date al valorii
parametrului actual la cel al parametrului formal.

 Puteti gasi tipurile de date necesare folosind


comanda DESCRIBE proc_name.

65
copyright@www.adrian.runceanu.ro

Întrebări?

66
Tehnici de programare cu baze de
date

#9 PL/SQL
Proceduri în PL/SQL (partea a II-a)

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 9

Proceduri în PL/SQL
(partea a II-a)

2
copyright@www.adrian.runceanu.ro

Cuprins
Proceduri în PL/SQL

1.Transmiterea parametrilor în
proceduri

3
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

 Pentru ca procedurile sa fie mai flexibile


este important ca diverse date sa fie fie
transmise procedurii prin parametrii de
intrare.

 Rezultatele determinate pot fi returnate


prin folosirea parametrilor de tip OUT sau
IN OUT.

4
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Tipuri de parametri procedurali

Tipurile parametrilor sunt specificate in


declararea parametrilor formali, dupa numele
parametrului si inainte de tipul sau de date.

5
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Tipurile parametrilor sunt:

1. parametru de tip IN (implicit) – furnizeaza date


de intrare subprogramului
2. parametru de tip OUT – returneaza rezultate de
la subprogram
3. parametru de tip IN OUT – furnizeaza o
valoare de intrare care poate fi returnata
modificata.

6
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Tipul implicit IN

Daca nu este specificat nici un tip


parametrului, atunci implicit este IN.

Sintaxa
CREATE PROCEDURE
procedure(param [mode] datatype)

7
copyright@www.adrian.runceanu.ro

Exemplu:
CREATE OR REPLACE PROCEDURE
raise_sal
(p_id IN emp.empno%TYPE, p_percent IN
NUMBER)
IS
BEGIN
UPDATE emp
SET sal = sal * (1 + p_percent/100)
WHERE empno = p_id;
END raise_sal;
Parametrii IN sunt doar date de intrare pentru
procedura.
Ei nu pot fi modificati in interiorul procedurii.

8
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Exemplu – folosirea parametrilor OUT

CREATE OR REPLACE PROCEDURE query_emp


(p_id IN emp.empno%TYPE,
p_name OUT emp.ename%TYPE,
p_sal OUT emp.sal%TYPE)
IS
BEGIN
SELECT ename, sal INTO p_name, p_sal
FROM emp
WHERE empno = p_id;
END query_emp;

9
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Exemplu – folosirea parametrilor OUT

10
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


DECLARE
a_emp_name emp.ename%TYPE;
a_emp_sal emp.sal%TYPE;
BEGIN
query_emp(7566, a_emp_name,
a_emp_sal);
DBMS_OUTPUT.PUT_LINE('Name: ' ||
a_emp_name);
DBMS_OUTPUT.PUT_LINE('sal: ' ||
a_emp_sal);
END;
11
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

12
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

13
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

14
copyright@www.adrian.runceanu.ro

 Procedura a fost creata pentru a extrage informatii


despre un anumit candidat.
 Procedura primeste valoarea 7566 pentru id-ul
angajatului si returneaza numele si salariul
angajatului cu id-ul 7566 in cei doi parametri OUT.
 Procedura query_emp are trei parametri formali.
 Doi dintre ei sunt de tip OUT care returneaza
valori programului appellant.
 Procedura primeste valoarea id-ului angajatului prin
intermediul parametrului p_id.
 Variabilele a_emp_name si a_emp_sal sunt
completate cu informatii preluate din interogare in
cei doi parametri OUT corespunzatori.

15
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Exemplu – folosirea parametrilor IN OUT

create or replace PROCEDURE


format_phone (p_phone_no IN OUT
VARCHAR2) IS
BEGIN
p_phone_no := '(' ||
SUBSTR(p_phone_no,1,4) || ')' ||
SUBSTR(p_phone_no,5,3) || '-' ||
SUBSTR(p_phone_no,8,3);
END format_phone;
16
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Exemplu – folosirea parametrilor IN OUT

17
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

 Folosind un parametru IN OUT, puteti


transmite o valoare procedurii care poate fi
modificata de procedura.

 Valoarea parametrului actual primita la apel


poate fi returnata in una dintre
urmatoarele variante:
1. valoarea initiala nemodificata
2. o noua valoare din procedura

18
copyright@www.adrian.runceanu.ro

In exemplul anterior:
 inainte de apel variabila p_phone_no are
valoarea '0720123456'
 dupa apel variabila p_phone_no are valoarea
'(0721)123-456'

Urmatorul cod creeaza un bloc anonim care


declara a_phone_no, ii atribuie un numar de
telefon neformatat si il transmite ca parametru
actual procedurii FORMAT_PHONE.
Procedura este executata si returneaza un sir de
caractere modificat in variabila a_phone_no care
este apoi afisata.

19
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

DECLARE
a_phone_no VARCHAR2(13);
BEGIN
a_phone_no := '0721123456';
format_phone (a_phone_no);
DBMS_OUTPUT.PUT_LINE('The
formatted phone number is: '||
a_phone_no);
END;

20
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

21
copyright@www.adrian.runceanu.ro

Sintaxa pentru transmiterea parametrilor


Sunt trei modalitati de transmitere a
parametrilor de la mediul apelant:

1. pozitional – listarea parametrilor actuali in aceeasi


ordine ca si cei formali
2. prin denumire – listarea parametrilor actuali intr-o
ordine arbitrara si folosirea operatorului de asociere
(=>) pentru a asocia un parametru formal denumit
cu parametrul actual corespunzator
3. combinat – listarea catorva parametri pozitionali
(fara operator special) si altii prin denumire (cu
operatorul =>)

22
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Exemple:

CREATE OR REPLACE PROCEDURE add_dept


( p_name IN dept.dname%TYPE,
p_loc IN dept.loc%TYPE)
IS
BEGIN
INSERT INTO dept(deptno, dname, loc)
VALUES (dept_seq.NEXTVAL, p_name, p_loc);
END add_dept;

23
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

24
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

1. Transmiterea prin notatie pozitionala


add_dept ('EDUCATION', 1400);

2. Transmiterea prin denumire


add_dept (p_loc=>1400,
p_name=>'EDUCATION');

3. Transmiterea prin notatie combinata


add_dept ('EDUCATION', p_loc=>1400);

25
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Urmatorul apel se va executa cu succes?

add_dept (p_loc => 1400, 'EDUCATION');

Raspuns:
Nu – deoarece atunci cand se foloseste notatia
combinata, parametrii notati pozitional trebuie sa fie
scrisi inaintea celor transmisi prin denumire.

26
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Urmatorul apel se va executa cu succes?

add_dept ('EDUCATION');

Raspuns:
Nu - trebuie furnizata o valoare pentru fiecare
parametru in afara de cazul cand parametrului
formal ii este atribuita o valoare implicita.

27
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri


Folosirea optiunii DEFAULT pentru parametrii IN

 Puteti atribui valori implicite parametrilor formali IN -


exemplu

CREATE OR REPLACE PROCEDURE add_dept (


p_name dept.dname%TYPE:='Unknown',
p_loc dept.loc%TYPE DEFAULT 1400)
IS
BEGIN
INSERT INTO dept (...)
VALUES (dept_seq.NEXTVAL, p_name, p_loc);
END add_dept;
28
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Codul prezinta doua modalitati de atribuire a


unei valori implicite unui parametru IN.
Cele doua modalitati prezentate folosesc:

1. operatorul de atribuire (:=) – pentru parametrul


p_name

2. optiunea DEFAULT – pentru operatorul p_loc

29
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

Prezentam trei modalitati de apelare a


procedurii add_dept

1. Atribuirea de valori implicite pentru fiecare


parametru
2. Combinarea notatiilor pozitionale si denumite
pentru atribuirea de valori
3. Folosirea de valori implicite pentru parametrii
cu nume si de valori transmise pentru ceilalti
parametri

30
copyright@www.adrian.runceanu.ro

1.Transmiterea parametrilor în proceduri

1. add_dept;

2. add_dept ('ADVERTISING', p_loc =>


1400);

3. add_dept (p_loc => 1400);

31
copyright@www.adrian.runceanu.ro

Reguli de folosire a optiunii DEFAULT pentru


parametri
 Nu puteti folosi valori implicite parametrilor OUT
si IN OUT in antet, dar acest lucru se poate realiza
in corpul procedurii.

 De obicei, puteti folosi denumirile pentru a


suprascrie valorile implicite ale parametrilor
formali. Totusi, nu puteti sari peste operatia de
transmitere a unui parametru actual daca nu este
nici o valoare implicita pentru parametrul formal.

 Un parametru care mosteneste o valoare implicita


este diferit de NULL.
32
copyright@www.adrian.runceanu.ro

Lucrul cu erorile de parametri in timpul rularii

 Toti parametrii pozitionali trebuie sa preceada parametrii


denumiti in apelul unui subprogram.
 Altfel este afisat un mesaj de eroare cum se arata in
urmatorul exemplu:
BEGIN
add_dept (name =>'new dept', 'new location');
END;

Se genereaza urmatorul mesaj de eroare:

33
copyright@www.adrian.runceanu.ro

Subprograme locale
Atunci cand o procedura apeleaza alta procedura,
in mod normal le cream separat.

CREATE OR REPLACE PROCEDURE subproc



END subproc;
CREATE OR REPLACE PROCEDURE mainproc

IS BEGIN

subproc (...);

END mainproc;

34
copyright@www.adrian.runceanu.ro

Dar se pot crea si impreuna ca o singura procedura.


CREATE OR REPLACE PROCEDURE mainproc

IS
PROCEDURE subproc (...) IS BEGIN

END subproc;
BEGIN

subproc (...);

END mainproc;

 Aici tot codul este intr-un singur loc si este mai usor de citit si
de intretinut.
 Domeniul unui subprogram imbricat este limitat la procedura in
care este definit;
 SUBPROC poate fi apelat din MAINPROC dar nu si din alt
subprogram sau din program. 35
copyright@www.adrian.runceanu.ro

Întrebări?

36
Tehnici de programare cu baze de
date

#10 PL/SQL
Functii în PL/SQL

Adrian Runceanu
www.runceanu.ro/adrian
2022 1
copyright@www.adrian.runceanu.ro

Curs 10

Funcţii în PL/SQL

2
copyright@www.adrian.runceanu.ro

Cuprins
Funcţii în PL/SQL

1. Crearea funcţiilor
2. Funcţii definite de utilizator
3. Modificarea şi suprimarea
subprogramelor PL/SQL
4. Module overload

3
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
O functie este un subprogram care
returneaza exact o valoare.
O procedura este o instructiune
executabila de sine statatoare, in timp ce o
functie poate exista doar ca o parte a unei
instructiuni executabile.
 O functie este un bloc PL/SQL cu nume care
accepta parametri IN optional si trebuie sa
returneze o singura valoare.
 Functiile sunt stocate in baza de date ca
obiecte ale schemei pentru executii repetate.
 O functie poate fi apelata ca parte a unei
expresii SQL sau a unei expresii PL/SQL. 4
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

1. In expresiile SQL o functie trebuie sa


indeplineasca reguli specifice pentru a controla
efectele secundare.

 Efectele secundare care trebuie evitate sunt:


◦ Orice tip de DML sau DDL
◦ COMMIT sau ROLLBACK
◦ Afectarea variabilelor globale

2. In expresiile PL/SQL identificatorul de functie


se comporta ca o variabila a carei valoare
depinde de parametrii care ii sunt transmisi.
5
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

Sintaxa pentru crearea functiilor

Antetul unei functii este asemanator cu


cel al unei proceduri, cu doua diferente:

 Tipul parametrilor trebuie sa fie doar IN

 Clauza RETURN este folosita in locul


parametrului de tip OUT

6
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
CREATE [OR REPLACE] FUNCTION
function_name
[(parameter1 [mode1] datatype1, ...)]
RETURN datatype IS|AS
[local_variable_declarations; …]
BEGIN
-- actions;
RETURN expression;
END [function_name];
Blocul PL/SQL trebuie sa aibă cel putin o
instructiune RETURN.
7
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
Observatii:
 O functie este un subprogram PL/SQL care
returneaza o singura valoare.
 Trebuie sa folositi o instructiune RETURN
pentru a rezulta o valoare cu un tip de date
care este continut in declararea tipului functiei
 Puteti crea functii noi cu ajutorul instructiunii
CREATE [OR REPLACE] FUNCTION care
poate avea declarata o lista de parametri,
trebuie sa returneze exact o valoare si trebuie
sa defineasca operatiile care se executa in
blocul PL/SQL.
8
copyright@www.adrian.runceanu.ro

Exemple:
1)
- Crearea functiei
CREATE OR REPLACE FUNCTION get_sal
(p_id emp.empno%TYPE)
RETURN NUMBER IS
v_sal emp.sal%TYPE := 0;
BEGIN
SELECT sal INTO v_sal
FROM emp
WHERE empno = p_id;
RETURN v_sal;
END get_sal;

- Apelarea functiei
... v_sal := get_sal(100);
9
copyright@www.adrian.runceanu.ro

Exemple:
1)
- Crearea functiei

10
copyright@www.adrian.runceanu.ro

2) Se poate folosi RETURN din sectiunea executabila


si/sau sectiunea EXCEPTION
- Crearea functiei
CREATE OR REPLACE FUNCTION get_sal
(p_id emp.empno%TYPE)
RETURN NUMBER IS
v_sal emp.sal%TYPE := 0;
BEGIN
SELECT sal INTO v_sal
FROM emp WHERE empno = p_id;
RETURN v_sal;
EXCEPTION
WHEN NO_DATA_FOUND THEN RETURN NULL;
END get_sal;
- Apelarea functiei ca o expresie cu un parametru
care nu este bun
... v_sal := get_sal(999);
11
copyright@www.adrian.runceanu.ro

2) Se poate folosi RETURN din sectiunea executabila


si/sau sectiunea EXCEPTION
- Crearea functiei

- Apelarea functiei ca o expresie cu un parametru


care nu este bun
... v_sal := get_sal(999);
12
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

Modalitati de apelare (sau executare) a


functiilor cu parametri
Functiile pot fi apelate in felul urmator:
1. Ca parte a expresiilor PL/SQL – se
foloseste o variabila locala intr-un bloc anonim
pentru a pastra valoarea returnata de functie
2. Ca parametru al unui alt subprogram –
transmiterea functiilor intre subprograme
3. Ca o expresie intr-o instructiune SQL –
apelarea unei functii ca pe oricare functie
single-row intr-o instructiune SQL
13
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
1. Apelarea ca o parte a unei expresii PL/SQL
cu folosirea unei variabile locale pentru a stoca
rezultatul obtinut:
DECLARE v_sal emp.sal%type;
BEGIN
v_sal := get_sal(100);
...
END;

14
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

2. Folosirea ca un parametru al altui subprogram

... DBMS_OUTPUT.PUT_LINE(get_sal(100));

3. Ca o expresie intr-o instructiune SQL

SELECT job_id, get_sal(empno)


FROM emp;

15
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
Apelarea functiilor fara parametri
Majoritatea functiilor au parametri, dar nu
toate.
USER si SYSDATE sunt functii sistem
fara parametri.
1. Apelarea ca parte a unei expresii PL/SQL
folosind o variabila locala pentru a obtine
rezultatul:
DECLARE v_today DATE;
BEGIN
v_today := SYSDATE;
...
END; 16
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

2. Folosirea ca parametru al altui subprogram

...
DBMS_OUTPUT.PUT_LINE(USER);

3. Folosirea intr-o instructiune SQL

SELECT job_id, SYSDATE-hiredate


FROM emp;

17
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
Avantajele si restrictiile functiilor
Avantaje Restrictii
Functiile ne permit sa afisam Tipurile de date PL/SQL nu se
temporar o valoare intr-un suprapun complet cu cele SQL
format nou
Dimensiunile PL/SQL nu sunt
aceleasi cu dimensiunile SQL.
Permit noi caracteristici cum ar
De exemplu o variabila VARCHAR2.
fi verificarea si analiza datelor
PL/SQL poate ajunge pana la 32KB,
iar o coloana SQL de tip
VARCHAR2 poate fi de maxim 4
KB.

18
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor

Diferente de sintaxa intre proceduri si


functii

Proceduri:
CREATE [OR REPLACE] PROCEDURE name
[parameters] IS|AS (Mandatory)
Variables, cursors, etc. (Optional)
BEGIN (Mandatory)
SQL and PL/SQL statements;
EXCEPTION (Optional)
WHEN exception-handling actions;
END [name]; (Mandatory) 19
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
Functii
CREATE [OR REPLACE] FUNCTION name
[parameters] (Mandatory)
RETURN datatype IS|AS (Mandatory)
Variables, cursors, etc. (Optional)
BEGIN (Mandatory)
SQL and PL/SQL statements;
RETURN ...; (One Mandatory, more
optional)
EXCEPTION (Optional)
WHEN exception-handling actions;
END [name]; (Mandatory) 20
copyright@www.adrian.runceanu.ro

1. Crearea funcţiilor
Proceduri Functii
Se executa ca o instructiune Se apeleaza ca parte a unei
PL/SQL expresii
Nu contine clauza RETURN in Trebuie sa contina clauza
antet RETURN in antet
Poate returna valori in parametrii Trebuie sa returneze o singura
de iesire valoare
Poate contine o instructiune Trebuie sa contina o instructiune
RETURN fara o valoare RETURN

 Ambele pot avea 0 sau mai multi parametri IN care pot


fi transmisi de la mediul apelant.

 Ambele au o structura de bloc standard ce include o


sectiune de manipulare a exceptiilor.
21
copyright@www.adrian.runceanu.ro

Caracteristici proceduri

 Puteti crea o procedura pentru a retine o


serie de operatii pentru o executie ulterioara.

 O procedura nu trebuie neaparat sa


returneze o valoare.

 O procedura poate apela o functie.

 O procedura care contine un singur


parametru OUT poate fi rescrisa ca o functie
care returneaza o valoare.
22
copyright@www.adrian.runceanu.ro

Caracteristici functii
 Functiile se pot folosi atunci cand dorim sa
transmitem o singura valoare mediului apelant.

 Valoarea este returnata cu ajutorul instructiunii


RETURN.

 Functiile utilizate in instructiunile SQL nu pot


folosi parametri de tip OUT si IN OUT.

 Totusi, o functie care are parametri de tip OUT


poate fi apelata de o procedura PL/SQL sau de
un bloc anonim.
23
copyright@www.adrian.runceanu.ro

Cuprins
Funcţii în PL/SQL

1. Crearea funcţiilor
2. Funcţii definite de utilizator
3. Modificarea şi suprimarea
subprogramelor PL/SQL
4. Module overload

24
copyright@www.adrian.runceanu.ro

2. Funcţii definite de utilizator


Functii definite de utilizator
 O functie definita de utilizator este o functie
care este creata de catre programator.
 GET_DEPT_NAME si CALCULATE_TAX sunt
exemple de functii definite de utilizator, in timp
ce UPPER, LOWER si LPAD sunt exemple de
functii sistem furnizate automat de Oracle.
 Majoritatea functiilor sistem (cum ar fi UPPER,
LOWER si LPAD) sunt stocate in pachete
denumite SYS.STANDARD.
 Aceste functii sistem se mai numesc functii
built-in. 25
copyright@www.adrian.runceanu.ro

2. Funcţii definite de utilizator


Avantajele functiilor in instructiunile SQL

 Prin folosirea functiilor in clauza WHERE a


instructiunii SELECT creste eficienta prin
eliminarea randurilor nedorite inainte ca
datele sa fie transmise aplicatiei.
 De exemplu, in sistemul administrativ al unei
facultati, doriti sa extrageti doar acei studenti
ale caror nume sunt stocate in intregime cu
majuscule. Acest lucru poate fi gasit pentru
putine randuri ale tabelei.
26
copyright@www.adrian.runceanu.ro

2. Funcţii definite de utilizator


 Instructiunea folosita este:

 Fara functia UPPER este nevoie sa


extrageti toate randurile referitoare la
studenti, sa le transmiteti in retea si sa le
eliminati pe cele nedorite prin aplicatie.

27
copyright@www.adrian.runceanu.ro

 In instructiunile SQL functiile pot manipula


valorile de tip data calendaristica.
 De exemplu, pentru un eveniment social de
la sfarsitul semestrului, vreti sa afisati (doar
ca amuzament) numele fiecarui profesor cu
caracterele inversate – de exemplu “Adrian
Runceanu” devine “unaecnuR nairdA”.

 Puteti crea o functie definita de utilizator


numita REVERSE_NAME care face acest
lucru, iar apoi codul:

28
copyright@www.adrian.runceanu.ro
 Functiile definite de utilizator pot extinde SQL
acolo unde operatiile sunt prea complexe,
prea incomode sau nu se pot realiza in mod
obisnuit cu SQL.
 De asemenea, functiile ne ajuta sa depasim
in mod repetat scrierea aceluiasi cod.
 De exemplu, daca vreti sa calculati cat timp a
muncit un angajat pentru un proiect rotunjit la
un numar intreg de luni, puteti crea o functie
definita de utilizator numita
HOW_MANY_MONTHS pentru a face acest
lucru.
 Apoi se poate folosi instructiunea:

29
copyright@www.adrian.runceanu.ro
Functii in SQL
Functii in expresii SQL – Exemple
CREATE OR REPLACE FUNCTION
tax(p_value IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (p_value * 0.08);
END tax;

Functii create
SELECT empno, ename, sal, tax(sal)
FROM emp
WHERE deptno = 50;
30
copyright@www.adrian.runceanu.ro

Unde puteti folosi functii definite de


utilizator in instructiunile SQL?
Functiile definite de utilizator se comporta
ca si functiile single-row de tip built-in – cum
ar fi UPPER, LOWER, LPAD.
Ele pot fi folosite in:
1. Lista de coloane a unei interogari SELECT
2. Expresii conditionale in clauzele WHERE si
HAVING
3. Clauzele ORDER BY si GROUP BY
4. Clauza VALUES din instructiunea INSERT
5. Clauza SET din instructiunea UPDATE

Adica, pot fi folosite oriunde putem scrie o


valoare a unei expresii. 31
copyright@www.adrian.runceanu.ro

Exemplu care arata functia definita de utilizator


cu numele TAX, care poate fi folosita in patru
locuri intr-o singura instructiune SELECT:

SELECT empno, tax(sal)


FROM emp
WHERE tax(sal) > (SELECT
MAX(tax(sal))
FROM emp
WHERE department_id = 20)
ORDER BY tax(sal) DESC;

32
copyright@www.adrian.runceanu.ro
Restrictii la utilizarea functiilor in
instructiunilor SQL
Pentru a folosi o functie definite de utilizator
intr-o instructiune SQL, functia trebuie sa
respecte regulile si restrictiile limbajului SQL:
1. Functia poate accepta doar tipurile de date
valide ale SQL-ului in parametrii IN si trebuie
sa returneze un tip de date valid al SQL-ului.
2. Tipurile specifice SQL, cum ar tipurile
BOOLEAN si %ROWTYPE nu sunt acceptate
3. Limitele impuse de catre SQL nu trebuie sa
fie depasite (PL/SQL permite variabile de tip
VARCHAR2 de pana la 32 KB, dar SQL nu
permite mai mult de 4 KB)
33
copyright@www.adrian.runceanu.ro

Restrictii la utilizarea functiilor in


instructiunilor SQL (continuare)
4. Parametrii trebuie sa fie specificati cu
ajutorul notatiei pozitionale. Notatia (=>) nu
este permisa.

Exemplu:
SELECT empno, tax(sal)
FROM emp;
SELECT empno, tax(p_value => sal)
FROM emp;

A doua instructiune SELECT are ca efect o


eroare. 34
copyright@www.adrian.runceanu.ro

Restrictii la utilizarea functiilor in


instructiunilor SQL (continuare)
5. Functiile folosite intr-o instructiune SELECT
nu pot contine instructiuni DML
6. Functiile folosite intr-o instructiune UPDATE
sau DELETE nu pot contine o interogare sau
o instr. DML pentru aceeasi tabela
7. Functiile folosite in orice instructiune SQL nu
pot termina tranzactiile (adica nu se pot
executa operatiile COMMIT sau ROLLBACK)
8. Functiile folosite in orice instr. SQL nu pot
utiliza comenzi DDL (de exemplu, CREATE
TABLE) sau comenzi DCL (de exemplu
ALTER SESSION) deoarece acestea implica
COMMIT 35
copyright@www.adrian.runceanu.ro

2. Funcţii definite de utilizator


Exemplu 1:

36
copyright@www.adrian.runceanu.ro

Exemplu 2
Urmatoarea functie interogheaza tabela
emp:

Cand folosim instr. DML, aceasta returneaza un


mesaj de “mutating table” asemanator cu
mesajul din exemplu anterior.

37
copyright@www.adrian.runceanu.ro

Cuprins
Funcţii în PL/SQL

1. Crearea funcţiilor
2. Funcţii definite de utilizator
3. Modificarea şi suprimarea
subprogramelor PL/SQL
4. Module overload

38
copyright@www.adrian.runceanu.ro

3. Modificarea şi suprimarea
subprogramelor PL/SQL
 Pentru a lua în considerare modificarea unei
proceduri sau funcţii, recompilarea acestora
se face prin comanda:

ALTER {FUNCTION | PROCEDURE}


[schema.]nume COMPILE;

 Comanda recompilează doar procedurile


catalogate standard.
 Procedurile unui pachet se recompilează
într-o altă manieră.
39
copyright@www.adrian.runceanu.ro

3. Modificarea şi suprimarea
subprogramelor PL/SQL
 Ca şi în cazul tabelelor, funcţiile şi
procedurile pot fi suprimate cu ajutorul
comenzii DROP.

 Aceasta presupune eliminarea


subprogramelor din dicţionarul datelor.

 DROP este o comandă ce aparţine limbajului


de definire a datelor(DDL), astfel că se
execută un COMMIT implicit atât înainte, cât
şi după comandă.
40
copyright@www.adrian.runceanu.ro

3. Modificarea şi suprimarea subprogramelor


PL/SQL

 Când este şters un subprogram prin


comanda DROP, automat sunt revocate
toate privilegiile acordate referitor la acest
subprogram.
 Dacă este utilizată sintaxa CREATE OR
REPLACE, privilegiile acordate asupra
acestui obiect (subprogram) rămân
aceleaşi.
DROP {FUNCTION | PROCEDURE}
[schema.]nume;
41
copyright@www.adrian.runceanu.ro

Cuprins
Funcţii în PL/SQL

1. Crearea funcţiilor
2. Funcţii definite de utilizator
3. Modificarea şi suprimarea
subprogramelor PL/SQL
4. Module overload

42
copyright@www.adrian.runceanu.ro

4. Module overload

 În anumite condiţii, două sau mai multe


module pot să aibă aceleaşi nume, dar să
difere prin lista parametrilor.

 Aceste module sunt numite module


overload (supraîncărcate).

 Funcţia TO_CHAR este un exemplu de


modul overload.

43
copyright@www.adrian.runceanu.ro

4. Module overload

 În cazul unui apel, compilatorul compară


parametri actuali cu listele parametrilor
formali pentru modulele overload şi
execută modulul corespunzător.

 Toate programele overload trebuie să fie


definite în acelaşi bloc PL/SQL (bloc
anonim, modul sau pachet).

 Nu poate fi definită o versiune într-un bloc,


iar altă versiune într-un bloc diferit.
44
copyright@www.adrian.runceanu.ro

4. Module overload

 Modulele overload pot să apară în


programele PL/SQL:

1. fie în secţiunea declarativă a unui bloc


2. fie în interiorul unui pachet

 Supraîncărcarea funcţiilor sau procedurilor


nu se poate face pentru funcţii sau
proceduri stocate, dar se poate face pentru
subprograme locale, subprograme care
apar în pachete sau pentru metode.

45
copyright@www.adrian.runceanu.ro

4. Module overload

Observaţii:
1. Două programe overload trebuie să difere,
cel puţin, prin tipul unuia dintre parametri.
Două programe nu pot fi overload dacă
parametri lor formali diferă numai prin
subtipurile lor şi dacă aceste subtipuri se
bazează pe acelaşi tip de date.

2. Nu este suficient ca lista parametrilor


programelor overload să difere numai prin
numele parametrilor formali.
46
copyright@www.adrian.runceanu.ro

4. Module overload

Observaţii (continuare):
3. Nu este suficient ca lista parametrilor
programelor overload să difere numai prin
tipul acestora (IN, OUT, IN OUT).
PL/SQL nu poate face diferenţe (la apelare)
între tipurile IN sau OUT.

4. Nu este suficient ca funcţiile overload să


difere doar prin tipul datei returnate (tipul
datei specificate în clauza RETURN a
funcţiei).
47
copyright@www.adrian.runceanu.ro

4. Module overload

Exemplu:
 Să se creeze două funcţii (locale) cu acelaşi
nume care să calculeze media salariilor din
departamentul 20.
 Prima funcţie va avea un argument
reprezentând numarul departamentului, iar
cea de a doua va avea două argumente, unul
reprezentând numarul departamentului, iar
celălalt reprezentând jobul pentru care se
calculează valoarea medie (adică funcţia va
calcula media salariilor pentru un anumit tip
de job). 48
copyright@www.adrian.runceanu.ro

4. Module overload

create or replace function "VALOARE_MEDIE"


(v_deptno in emp.deptno%TYPE)
return NUMBER is
medie NUMBER(7,2);
BEGIN
SELECT AVG(sal)
INTO medie
FROM emp
WHERE deptno = v_deptno;
RETURN medie;
END;
49
copyright@www.adrian.runceanu.ro

4. Module overload
create or replace function "VALOARE_ MEDIE1"
(v_deptno in NUMBER, v_job in VARCHAR2)
RETURN NUMBER IS
medie NUMBER(10,2);
BEGIN
SELECT AVG(sal)
INTO medie
FROM emp
WHERE deptno = v_deptno AND job = v_job;
RETURN medie;
END;
50
copyright@www.adrian.runceanu.ro

4. Module overload
DECLARE
medie1 NUMBER(10,2);
medie2 NUMBER(10,2);
BEGIN
medie1 := valoare_medie(20);
DBMS_OUTPUT.PUT_LINE('Media salariilor
din departamentul 20 este ' || medie1);
medie2 := valoare_medie1(20, 'ANALYST');
DBMS_OUTPUT.PUT_LINE('Media salariilor
din departamentul 20 care au functia de
ANALYST este ' || medie2);
END;
51
copyright@www.adrian.runceanu.ro

4. Module overload

52
copyright@www.adrian.runceanu.ro

4. Module overload

53
copyright@www.adrian.runceanu.ro

Întrebări?

54
Tehnici de programare cu baze de
date

#11 PL/SQL
Functii în PL/SQL (partea II-a)

Adrian Runceanu
www.runceanu.ro/adrian
2022
Curs 11

Funcţii în PL/SQL
(partea II)
Cuprins
Funcţii în PL/SQL(partea II)

1. Recursivitate
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
3. Informaţii referitoare la subprograme
4. Dependenţa subprogramelor
1. Recursivitate
 Un subprogram recursiv presupune că
acesta se apelează pe el însuşi.
 În Oracle o problemă delicată este legată de
locul unde se plasează un apel recursiv.
 De exemplu, dacă apelul este în interiorul
unui cursor FOR sau între comenzile OPEN
şi CLOSE, atunci la fiecare apel este
deschis alt cursor.
 În felul acesta, programul poate depăşi
limita pentru OPEN_CURSORS setată în
parametrul de iniţializare Oracle.
1. Recursivitate
Exemplu:

Să se calculeze recursiv al m-lea termen din şirul


lui Fibonacci.

FUNCTION fibonacci(m INTEGER)


RETURN INTEGER IS
BEGIN
IF (m = 1) OR (m = 2) THEN
RETURN 1;
ELSE
RETURN fibonacci(m-1) + fibonacci(m-2);
END IF;
END fibonacci;
1. Recursivitate
Declaraţii forward

 Subprogramele sunt reciproc recursive dacă


ele se apelează unul pe altul direct sau
indirect.
 Declaraţiile forward permit definirea
subprogramelor reciproc recursive.
 În PL/SQL, un identificator trebuie declarat
înainte de a-l folosi.
 De asemenea, un subprogram trebuie
declarat înainte de a-l apela.
1. Recursivitate
PROCEDURE alfa ( ... ) IS
BEGIN
beta( ... ); -- apel incorect
...
END;
PROCEDURE beta ( ... ) IS
BEGIN
...
END;
 Procedura beta nu poate fi apelată deoarece nu este încă
declarată.
 Problema se poate rezolva simplu, inversând ordinea celor
două proceduri.
 Această soluţie nu este eficientă întotdeauna.
1. Recursivitate
 PL/SQL permite un tip special de declarare a unui
subprogram numit forward.
 El constă dintr-o specificare de subprogram
terminată prin “;”.
PROCEDURE beta ( ... ); -- declaraţie forward
..
PROCEDURE alfa ( ... ) IS
BEGIN
beta( ... );
...
END;
PROCEDURE beta ( ... ) IS
BEGIN
...
END;
1. Recursivitate

Se pot folosi declaraţii forward:

 pentru a defini subprograme într-o anumită


ordine logică

 pentru a defini subprograme reciproc


recursive

 pentru a grupa subprograme într-un pachet


1. Recursivitate

 Lista parametrilor formali din declaraţia


forward trebuie să fie identică cu cea
corespunzătoare corpului subprogramului.

 Corpul subprogramului poate apărea


oriunde după declaraţia sa forward, dar
trebuie să rămână în aceeaşi unitate de
program.
Cuprins
Funcţii în PL/SQL(partea II)

1. Recursivitate
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
3. Informaţii referitoare la subprograme
4. Dependenţa subprogramelor
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator

 Începând cuvarianta Oracle Release 7.1,


o funcţie stocată poate fi referită într-o
comandă SQL la fel ca orice funcţie
standard furnizată de sistem (built-in
function), dar cu anumite restricţii.

 Funcţiile PL/SQL definite de utilizator pot fi


apelate din orice expresie SQL în care pot
fi folosite funcţii SQL standard.
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
Funcţiile PL/SQL pot să apară în:

1. lista de selecţie a comenzii SELECT

2. condiţia clauzelor WHERE şi HAVING

3. clauzele CONNECT BY, START WITH,


ORDER BY şi GROUP BY

4. clauza VALUES a comenzii INSERT

5. clauza SET a comenzii UPDATE


2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
Exemplu:
Să se afişeze salariile (nume angajat, salariu, job) a
căror valoare este mai mare decât valoarea
medie a tuturor salariilor din firma.
create or replace function "VALOARE_MEDIE2“
return NUMBER is
v_val_mediu emp.sal%TYPE;
begin
SELECT AVG(sal)
INTO v_val_mediu
FROM emp;
RETURN v_val_mediu;
end;
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator

Referirea acestei funcţii într-o comanda


SQL se poate face prin:

SELECT ename, sal, job


FROM emp
WHERE sal >= valoare_medie2;
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator

Există restricţii referitoare la folosirea funcţiilor


definite de utilizator într-o comandă SQL.
Câteva dintre acestea, care s-au păstrat şi
pentru versiunile ulterioare Oracle9i:
1. funcţia definită de utilizator trebuie să fie o funcţie
stocată (procedurile stocate nu pot fi apelate în
expresii SQL), nu poate fi locală unui alt bloc
2. funcţia definită de utilizator trebuie să fie o funcţie
linie şi nu una grup (restricţia dispare în Oracle9i)
3. funcţia apelată dintr-o comandă SELECT, sau din
comenzi DML: INSERT, UPDATE şi DELETE nu
poate modifica tabelele bazei de date
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
4. funcţia apelată dintr-o comandă UPDATE sau
DELETE nu poate interoga sau modifica tabele ale
bazei reactualizate chiar de aceste comenzi (table
mutating)
5. funcţia apelată din comenzile SELECT, INSERT,
UPDATE sau DELETE nu poate executa comenzi
LCD (COMMIT), ALTER SYSTEM, SET ROLE sau
comenzi LDD (CREATE)
6. funcţia nu poate să apară în clauza CHECK a unei
comenzi CREATE/ALTER TABLE
7. funcţia nu poate fi folosită pentru a specifica o
valoare implicită pentru o coloană în cadrul unei
comenzi CREATE/ALTER TABLE
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
8. funcţia poate fi utilizată într-o comandă SQL
numai de către proprietarul funcţiei sau de
utilizatorul care are privilegiul EXECUTE asupra
acesteia

9. funcţia definită de utilizator, apelabilă dintr-o


comandă SQL, trebuie să aibă doar parametri
de tip IN, cei de tip OUT şi IN OUT nefiind
acceptaţi

10. parametrii unei funcţii PL/SQL apelate dintr-o


comandă SQL trebuie să fie specificaţi prin
poziţie (specificarea prin nume nefiind permisă)
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
11. parametrii formali ai unui subprogram funcţie
trebuie să fie de tip specific bazei de date
(NUMBER, CHAR, VARCHAR2, ROWID,
LONG, LONGROW, DATE), nu tipuri PL/SQL
(BOOLEAN sau RECORD)

12. tipul returnat de un subprogram funcţie trebuie


să fie un tip intern pentru server, nu un tip
PL/SQL

13. funcţia nu poate apela un subprogram care nu


respectă restricţiile anterioare
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator

Exemplu de restrictie a utilizarii functiilor in


comenzi SQL:

Restrictia
4. funcţia apelată dintr-o comandă UPDATE
sau DELETE nu poate interoga sau modifica
tabele ale bazei reactualizate chiar de aceste
comenzi (table mutating)

 Comanda UPDATE va returna o eroare


deoarece tabelul emp este mutating.
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
Cuprins
Funcţii în PL/SQL(partea II)

1. Recursivitate
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
3. Informaţii referitoare la subprograme
4. Dependenţa subprogramelor
3. Informaţii referitoare la subprograme
Informaţiile referitoare la subprogramele PL/SQL şi
modul de acces la aceste informaţii sunt următoarele:

 codul sursă, utilizând vizualizarea USER_SOURCE


din dicţionarul datelor (DD)
 informaţii generale, utilizând vizualizarea
USER_OBJECTS din dicţionarul datelor
 tipul parametrilor (IN, OUT, IN OUT), utilizând
comanda DESCRIBE
 erorile la compilare, utilizând vizualizarea
USER_ERRORS din dicţionarul datelor sau comanda
SHOW ERRORS
 informaţii de depanare, utilizând pachetul
DBMS_OUTPUT.
3. Informaţii referitoare la subprograme
Vizualizarea USER_OBJECTS conţine informaţii
generale despre toate obiectele manipulate în BD, în
particular şi despre subprogramele stocate.

Vizualizarea USER_OBJECTS are următoarele


câmpuri:

1. OBJECT_NAME – numele obiectului


2. OBJECT_TYPE – tipul obiectului (PROCEDURE, FUNCTION
etc.)
3. OBJECT_ID – identificator intern al obiectului
4. CREATED – data când obiectul a fost creat
5. LAST_DDL_TIME – data ultimei modificări a obiectului
6. TIMESTAMP – data şi momentul ultimei recompilări
7. STATUS – starea obiectului (VALID sau INVALID)
3. Informaţii referitoare la subprograme
Pentru a verifica dacă recompilarea explicită
(ALTER) sau implicită a avut succes se
poate verifica starea subprogramelor
utilizând USER_OBJECTS.

Orice obiect are o stare (status) sesizată în


DD, care poate fi:
 VALID (obiectul a fost compilat şi poate fi
folosit când este referit)
 INVALID (obiectul trebuie compilat înainte
de a fi folosit)
3. Informaţii referitoare la subprograme

Exemplu:

Să se listeze
procedurile şi
funcţiile deţinute de
utilizatorul curent,
precum şi starea
acestora.
3. Informaţii referitoare la subprograme
După ce subprogramul a fost creat, codul
sursă al acestuia poate fi obţinut
consultând vizualizarea USER_SOURCE
din DD, care are următoarele câmpuri:

1. NAME - numele obiectului


2. TYPE - tipul obiectului
3. LINE - numărul liniei din codul sursă
4. TEXT - textul liniilor codului sursă
3. Informaţii referitoare la subprograme
Exemplu:
Să se afişeze codul complet pentru funcţia
valoare_medie.

SELECT TEXT
FROM USER_SOURCE
WHERE NAME = ‘valoare_medie’
ORDER BY LINE;
3. Informaţii referitoare la subprograme
Exemplu:
Să se scrie o procedură care recompilează toate
obiectele invalide din schema personală.
CREATE OR REPLACE PROCEDURE sterge IS
CURSOR obj_curs IS
SELECT OBJECT_TYPE, OBJECT_NAME
FROM USER_OBJECTS
WHERE STATUS = 'INVALID'
AND OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION',
PACKAGE', 'PACKAGE BODY', 'VIEW');
BEGIN
FOR obj_rec IN obj_curs LOOP
DBMS_DDL.ALTER_COMPILE(obj_rec.OBJECT_TYPE,
USER, obj_rec.OBJECT_NAME);
END LOOP;
END sterge;
3. Informaţii referitoare la subprograme
 Dacă se recompilează un obiect PL/SQL,
atunci server-ul va recompila orice obiect
invalid de care depinde.

 Dacă recompilarea automată implicită a


procedurilor locale dependente are
probleme, atunci starea obiectului va
rămâne INVALID şi server-ul Oracle
semnalează eroare.
3. Informaţii referitoare la subprograme
Deci:

 este preferabil ca recompilarea să fie


manuală (recompilare explicită utilizând
comanda ALTER: PROCEDURE,
FUNCTION, TRIGGER, PACKAGE) cu
opţiunea COMPILE

 este necesar ca recompilarea să se facă


cât mai repede, după definirea unei
schimbări referitoare la obiectele bazei
Cuprins
Funcţii în PL/SQL(partea II)

1. Recursivitate
2. Utilizarea în expresii SQL a funcţiilor
definite de utilizator
3. Informaţii referitoare la subprograme
4. Dependenţa subprogramelor
4. Dependenţa subprogramelor
 Când este compilat un subprogram, toate
obiectele Oracle care sunt referite vor fi
înregistrate în dicţionarul datelor (DD).
 Subprogramul este dependent de aceste
obiecte.
 Un subprogram care are erori la compilare
este marcat ca “invalid” în dicţionarul
datelor.
 Un subprogram stocat poate deveni, de
asemenea, invalid dacă o operaţie LDD
este executată asupra unui obiect de care
depinde.
4. Dependenţa subprogramelor

Obiecte dependente Obiecte referite


View Table
Procedure View
Function Procedure
Package Specification Function
Package Body Synonym
Database Trigger Package Specification
4. Dependenţa subprogramelor
Dacă se modifică definiţia unui obiect referit,
obiectul dependent poate (sau nu) să continue să
funcţioneze normal.

Există două tipuri de dependenţe:


1. dependenţă directă, în care obiectul dependent
(procedure sau function) face referinţă direct la
un table, view, sequence, procedure, function.
2. dependenţă indirectă, în care obiectul
dependent (procedure sau function) face
referinţă indirect la un table, view, sequence,
procedure, function prin intermediul unui view,
procedure sau function.
Testare

1. Exemple de funcţii
2. Probleme propuse spre rezolvare
1. Exemple de funcţii
Functie care calculeaza circumferinta unui cerc:
FUNCTION circumf (angle NUMBER:=360,radius
NUMBER)
RETURN NUMBER IS
pi CONSTANT NUMBER := 3.1415926;
BEGIN
RETURN ROUND((angle/360)*2*pi*radius,2);
END;
1. Exemple de funcţii
Functie care verifica daca un numar este par
CREATE OR REPLACE FUNCTION is_even(num_in NUMBER)
RETURN BOOLEAN IS
BEGIN
IF MOD(num_in, 2) = 0 THEN
RETURN TRUE;
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END is_even;
1. Exemple de funcţii
Functie care verifica daca un numar este impar
Testare

1. Exemple de funcţii
2. Probleme propuse spre rezolvare
2. Probleme propuse spre rezolvare
2. Probleme propuse spre rezolvare
1. Să se declare o procedură locală într-un
bloc PL/SQL anonim prin care să se
introducă în tabelul DEPARTAMENTE_PNU
o nouă înregistrare precizând, prin
intermediul parametrilor, valori pentru toate
câmpurile.
Invocaţi procedura în cadrul blocului.
Interogaţi tabelul DEPARTAMENTE_PNU şi
apoi anulaţi modificările (ROLLBACK).
2. Probleme propuse spre rezolvare
2. Să se declare o procedură locală care are parametrii
următori:
- p_rezultat (parametru de tip OUT) de tipul coloanei
last_name din tabelul ANGAJATI_PNU;
- p_comision (parametru de tip IN) de tipul coloanei
commission_pct din ANGAJATI_PNU, iniţializat cu
NULL;
- p_cod (parametru de tip IN) de tipul coloanei
employee_id din ANGAJATI_PNU, iniţializat cu NULL.
Dacă p_comision nu este NULL atunci în p_rezultat se va memora
numele salariatului care are salariul maxim printre salariaţii având
comisionul respectiv.
În caz contrar, în p_rezultat se va memora numele salariatului al
cărui cod are valoarea dată la apelarea procedurii.
2. Probleme propuse spre rezolvare

3. Să se creeze o procedură stocată fără


parametri care afişează un mesaj
“Programare PL/SQL”, ziua de astăzi în
formatul DD-MONTH-YYYY şi ora curentă,
precum şi ziua de ieri în formatul DD-MON-
YYYY.
2. Probleme propuse spre rezolvare

4. Să se creeze o procedură stocată care


pentru un anumit cod de departament (dat
ca parametru) calculează prin intermediul
unor funcţii locale numărul de salariaţi care
lucrează în el, suma salariilor şi numărul
managerilor salariaţilor care lucrează în
departamentul respectiv.
2. Probleme propuse spre rezolvare

5. Să se creeze o funcţie stocată care


determină numărul de salariaţi din
problema4_pnu angajaţi după 1995, într-un
departament dat ca parametru.
Să se apeleze această funcţie într-un bloc
PL/SQL.
2. Probleme propuse spre rezolvare

6. Să se calculeze recursiv numărul de


permutări ale unei mulţimi cu n elemente,
unde n va fi transmis ca parametru.
2. Probleme propuse spre rezolvare

7. Să se afişeze numele, job-ul şi salariul


angajaţilor al căror salariu este mai mare
decât media salariilor din tabelul
angajati_pnu.
Întrebări?
Tehnici de programare cu baze de
date

#12 PL/SQL
Pachete în PL/SQL

Adrian Runceanu
www.runceanu.ro/adrian
2022
Curs 12

Pachete în PL/SQL
Cuprins
Pachete în PL/SQL

1. Crearea pachetelor
1.1. Specificatia pachetului
1.2. Corpul pachetului
2. Gestionarea conceptelor pachetului
3. Concepte avansate despre pachete
1. Crearea pachetelor
 Am studiat pana acum cum sa cream si cum sa
folosim procedurile si functiile.
 Sa presupunem ca vrem sa cream cateva
proceduri si/sau functii care sunt in relatie unele
cu altele.
 O aplicatie poate sa le foloseasca fie pe toate, fie
pe nici una dintre ele.
1. Crearea pachetelor

 Nu ar fi mai usor sa creati si sa administrati


toate subprogramele ca un singur obiect al
bazei de date: un pachet?

 In continuare vom studia ce este un pachet si


care sunt componentele sale.

 De asemenea, vom studia crearea si utilizarea


pachetelor.
1. Crearea pachetelor
Ce sunt pachetele PL/SQL?

 Pachetele PL/SQL sunt containere care ne permit sa


grupam impreuna subprograme, variabile, cursori si
exceptii PL/SQL in relatie unele cu altele.
 De exemplu, un pachet pentru Resurse Umane
poate contine:
◦ proceduri de angajare si concediere
◦ functii pentru calcularea comisioanelor si bonusurilor
◦ variabile folosite pentru scutirea de impozit
1. Crearea pachetelor

Componentele unui pachet PL/SQL

Un pachet este format din doua parti stocate


separat in baza de date:

1. Specificatia pachetului – interfata catre


aplicatie
2. Corpul pachetului – contine codul executabil
al subprogramelor care au fost declarate in
specificatia pachetului
1. Crearea pachetelor
Componentele unui pachet PL/SQL

1. Specificatia pachetului – interfata catre aplicatie.


Aceasta trebuie creata prima data. Se declara
constructorii (proceduri, functii, variabile, etc.) care
sunt vizibili in mediul apelant

2. Corpul pachetului – contine codul executabil al


subprogramelor care au fost declarate in specificatia
pachetului. De asemenea, poate contine propriile
declaratii de variabile.
Specificatia Corpul
pachetului pachetului

 Corpul detaliat al codului corpului corespunzator


pachetului nu este vizibil in mediul apelant, acesta
putand vedea doar specificatia.
 Daca sunt necesare modificari in cod, corpul de
instructiuni poate fi editat si recompilat fara a fi
necesara editarea sau recompilarea specificatiei.
 Aceasta structura formata din doua parti este un
exemplu al principiului programarii structurate numit
încapsulare.
Cuprins
Pachete în PL/SQL

1. Crearea pachetelor
1.1. Specificatia pachetului
1.2. Corpul pachetului
2. Gestionarea conceptelor pachetului
3. Concepte avansate despre pachete
1.1. Specificatia pachetului
Sintaxa pentru crearea specificatiei
pachetului
Pentru crearea pachetelor, declaram toti
constructorii publici in specificatia pachetului.

CREATE [OR REPLACE] PACKAGE package_name


IS|AS
public type and variable declarations
public subprogram specifications
END [package_name];
 Optiunea OR REPLACE sterge si recreaza specificatia
pachetului.
 Variabilele declarate in specificatia pachetului sunt
initializate implicit cu NULL.
 Toti constructorii declarati in specificatia pachetului
sunt vizibili utilizatorilor carora li s-a acordat privilegiul
EXECUTE asupra pachetului.
 package_name – specifica un nume pentru pachet
care trebuie sa fie unic printre obiectele din propria
schema. Includerea denumirii pachetului dupa
cuvantul cheie END este optionala.
 public type and variable declarations – declara
variabilele, constantele, cursorii, exceptiile, tipurile si
subtipurile definite de utilizator care sunt publice.
 public subprogram specifications – declara
procedurile si/sau functiile publice ale pachetului.
 “Public” presupune ca, constructorii
pachetului (variabile, procedurii, functii etc.)
pot fi vazuti si executati dinafara pachetului.
 Toti constructorii declarati in specificatia
pachetului sunt automat constructori publici.
 Specificatia pachetului ar trebui sa contina antete
de proceduri si functii terminate prin punct si
virgula, fara cuvantul cheie IS (sau AS) si blocul
sau PL/SQL.

 Implementarea (scrierea detaliata a codului) unei


proceduri sau functii care este declarata in
specificatia pachetului se face in corpul pachetului.
Exemple:
Specificarea pachetului check_emp_pkg
create or replace package CHECK_EMP_PKG as
g_max_length_of_service CONSTANT NUMBER
:= 100;
PROCEDURE chk_hiredate (p_date IN
emp.hiredate%TYPE);
PROCEDURE chk_dept_mgr (p_empid IN
emp.empno%TYPE, p_mgr IN emp.mgr%TYPE);
end;

g_max_length_of_service este o constanta declarata


si initializata in specificatie
chk_hiredate si chk_dept_mgr sunt doua proceduri
publice declarate in specificatie. Codul detaliat este
scris in corpul de instructiuni al pachetului.
Exemple:
Specificarea pachetului check_emp_pkg
Sa ne reamintim ca un tip de variabila este si cursorul.

create or replace package MANAGE_JOBS_PKG as

g_todays_date DATE := SYSDATE;


CURSOR jobs_curs IS
SELECT empno, job
FROM emp
ORDER BY empno;
PROCEDURE update_job (
p_emp_id IN emp.empno%TYPE);
PROCEDURE fetch_emps (
p_job_id IN emp.job%TYPE,
p_emp_id OUT emp.empno%TYPE);

end;
Specificarea pachetului MANAGE_JOBS_PKG
Cuprins
Pachete în PL/SQL

1. Crearea pachetelor
1.1. Specificatia pachetului
1.2. Corpul pachetului
2. Gestionarea conceptelor pachetului
3. Concepte avansate despre pachete
1.2. Corpul pachetului
Sintaxa pentru crearea corpului
pachetului

CREATE [OR REPLACE] PACKAGE BODY


package_name
IS|AS
private type and variable declarations
subprogram bodies
[BEGIN initialization statements]
END [package_name];
1.2. Corpul pachetului
 Optiunea OR REPLACE sterge si recreaza
corpul de instructiuni al pachetului.
 „Subprogram bodies” trebuie sa contina corpul
tuturor subprogramelor declarate in specificatia
pachetului
 package_name specifica un nume pentru
pachet care trebuie sa fie acelasi ca si la
specificatia pachetului. Folosirea denumirii
pachetului dupa cuvantul cheie END este
optionala.
 subprogram bodies – specifica implementarea
completa (codul PL/SQL detaliat) al tuturor
procedurilor si functiilor publice si/sau private.
1.2. Corpul pachetului
Atunci cand cream corpul unui pachet,
trebuie sa facem urmatoarele:
 Specificam optiunea OR REPLACE pentru a
suprascrie un corp de pachet existent
 Definim subprogramele intr-o ordine
corespunzatoare.
 Principiul de baza este ca trebuie sa declaram
o variabila sau un subprogram inainte ca
acestea sa fie referite de alte componente ale
aceluiasi pachet.
 Fiecare subprogram declarat in specificatia
pachetului trebuie de asemenea sa fie inclus
in corpul pachetului.
1.2. Corpul pachetului
Exemplu de corp al unui pachet: check_emp_pkg
CREATE OR REPLACE PACKAGE BODY
check_emp_pkg IS
PROCEDURE chk_hiredate
(p_date IN emp.hiredate%TYPE)
IS BEGIN
IF MONTHS_BETWEEN(SYSDATE,
p_date) > g_max_length_of_service * 12
THEN
RAISE_APPLICATION_ERROR(-
20200, 'Invalid Hiredate');
END IF;
END chk_hiredate;
1.2. Corpul pachetului
PROCEDURE chk_dept_mgr
(p_empid IN emp.empno%TYPE,
p_mgr IN emp.mgr%TYPE)
IS BEGIN

END chk_dept_mgr;
END check_emp_pkg;
1.2. Corpul pachetului
1.2. Corpul pachetului
Modificarea codului din corpul pachetului
 Sa presupunem ca vrem sa facem o modificare
in procedura chk_hiredate, de exemplu sa
punem un mesaj de eroare diferit.
 Trebuie sa editam si sa recompilam corpul
pachetului, dar nu trebuie sa recompilam
specificatia.
 Sa nu uitam ca specificatia poate exista fara
corp, dar corpul nu poate exista fara specificatie.
 Deoarece specificatia nu este recompilata, nu
este necesar sa recompilati nici o aplicatie (sau
subprogram PL/SQL) care deja apeleaza
procedurile pachetului.
1.2. Corpul pachetului
Recompilarea corpului pachetului: check_emp_pkg

CREATE OR REPLACE PACKAGE BODY


check_emp_pkg IS
PROCEDURE chk_hiredate
(p_date IN emp.hiredate%TYPE)
IS BEGIN
IF MONTHS_BETWEEN(SYSDATE, p_date) >
g_max_length_of_service * 12 THEN
RAISE_APPLICATION_ERROR(-20201,
'Hiredate Too Old');
END IF;
END chk_hiredate;
1.2. Corpul pachetului
PROCEDURE chk_dept_mgr
(p_empid IN emp.empno%TYPE,
p_mgr IN emp.mgr%TYPE)

IS BEGIN
...
END chk_dept_mgr;

END check_emp_pkg;
1.2. Corpul pachetului
1.2. Corpul pachetului
Apelarea subprogramelor in pachete
Procedurile si functiile din pachete se apeleaza
in acelasi mod ca si subprogramele care nu fac parte
din pachete, cu exceptia faptului ca trebuie sa
prefixam numele subprogramului cu numele
pachetului urmat de caracterul punct.
De exemplu:
 Dar daca se intampla sa uitati denumirile procedurilor
sau ce parametri trebuie sa le transmiteti?
 In astfel de situatii puteti folosi DESCRIBE in acelasi
mod in care folositi pentru o tabela sau pentru un view.
DESCRIBE check_emp_pkg
1.2. Corpul pachetului
Argumente pentru folosirea pachetelor
1. Modularitate – Programele si variabilele
relationate pot fi grupate impreuna.
2. Ascunderea informatiei – doar declaratiile
din specificatia pachetului sunt vizibile la
apel. Dezvoltatorii de aplicatii nu au nevoie
sa stie detaliile codului din corpul pachetului.
3. O intretinere mai usoara – Puteti modifica
si recompila codul din corpul pachetului fara
a fi necesara recompilarea specificatiei. De
aceea, aplicatiile care deja folosesc pachetul
nu este nevoie sa fie recompilate.
Cuprins
Pachete în PL/SQL

1. Crearea pachetelor
1.1. Specificatia pachetului
1.2. Corpul pachetului
2. Gestionarea conceptelor pachetului
3. Concepte avansate despre pachete
2. Gestionarea conceptelor
pachetului
Vom studia:
 Crearea subprogramelor private in
interiorul pachetului.

 Stergerea pachetelor

 Vizualizarea pachetelor in Data


Dictionary

 Beneficiile suplimentare ale pachetelor


2. Gestionarea conceptelor
pachetului
Componentele unui pachet PL/SQL

1. Componente publice – cele care sunt


declarate in specificatia pachetului.
◦ Componentele publice pot fi apelate din orice mediu
apelant, cu conditia ca utilizatorului sa-i fi fost acordat
privilegiul EXECUTE asupra pachetului.
2. Componente private - sunt declarate doar in
corpul pachetului si pot fi referite doar de alt
constructor (public sau privat) din acelasi corp al
pachetului.
◦ Componentele private pot referi componentele
publice ale pachetului.
2. Gestionarea conceptelor
pachetului

Vizibilitatea componentelor pachetului

 Vizibilitatea unei componente descrie daca


acea componenta poate fi vazuta, referita si
folosita de alte componente sau obiecte.

 Vizibilitatea unei componente depinde de


locul unde este declarata.
2. Gestionarea conceptelor
pachetului
Vizibilitatea componentelor pachetului

Puteti declara componentele in 3 locuri din


interiorul pachetului:
1. Global, in specificatie – aceste componente sunt
vizibile in tot corpul pachetului si de catre mediul
apelant.
2. Local, in corpul pachetului, dar in afara oricarui
subprogram – aceste componente sunt vizibile pe
parcursul intregului corp al pachetului, dar nu si de
mediul apelant
3. Local, in corpul pachetului, in interiorul unui anumit
subprogram – aceste componente sunt vizibile doar in
acel subprogram.

Toate componentele publice sunt globale, iar


componentele private sunt locale.
Care este totusi diferenta intre public si global, intre
privat si local? Intr-adevar nici una.

Dar se foloseste:
 public/privat cand vorbim despre proceduri si functii
 global/local cand este vorba despre alte
componente (variabile, constante, cursori).
2. Gestionarea conceptelor
pachetului
Vizibilitatea componentelor publice (globale)

Componentele declarate global sunt vizibile in


interiorul si in exteriorul pachetului, astfel:

 O variabila globala declarata in specificatia


pachetului poate fi referita si modificata in afara
pachetului

 Un subprogram public declarat in specificatie


poate fi apelat din surse de cod extern
2. Gestionarea conceptelor
pachetului
Vizibilitatea componentelor private (locale)
Componentele locale sunt vizibile doar in
structura in care sunt declarate, astfel:
 Variabilele locale declarate intr-un anumit
subprogram pot fi referite doar de acel
subprogram si nu sunt vizibile de catre
componentele externe
 Variabilele locale care sunt declarate in corpul
unui pachet pot fi referite de celelalte
componente din acelasi corp al pachetului. Nu
sunt vizibile nici unui subprogram sau obiect
care sunt in afara pachetului.
Exemplu – specificatia pachetului sal_pkg

Sa presupunem sa avem o regula in domeniul de


activitate ca salariul nici unui angajat sa nu creasca
cu mai mult de 20% la un moment dat.

CREATE OR REPLACE PACKAGE sal_pkg


IS
g_max_sal_raise CONSTANT NUMBER := 0.20;
PROCEDURE update_sal
(p_empno emp.empno%TYPE, p_new_sal
emp.sal%TYPE);
END sal_pkg;
g_max_sal_raise este o constanta globala initializata
cu 0.20
update_sal este o procedura publica care actualizeaza
salariul angajatului.
Exemplu de corp – pachet sal_pkg

CREATE OR REPLACE PACKAGE BODY sal_pkg IS


FUNCTION validate_raise -- private function
(p_old_sal emp.sal%TYPE,
p_new_sal emp.sal%TYPE)
RETURN BOOLEAN IS
BEGIN
IF p_new_sal > (p_old_sal * (1 +
g_max_sal_raise)) THEN RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END validate_raise;

… -- in continuare procedura publica



PROCEDURE update_sal -- public procedure
(p_empno emp.empno%TYPE,
p_new_sal emp.sal%TYPE)
IS
v_old_sal emp.sal%TYPE; -- local variable
BEGIN
SELECT sal INTO v_old_sal
FROM emp
WHERE empno = p_empno;
IF validate_raise(v_old_sal, p_new_sal) THEN
UPDATE emp SET sal = p_new_sal
WHERE empno = p_empno;
ELSE
RAISE_APPLICATION_ERROR(-20210, 'Raise too
high');
END IF;
END update_sal;
END sal_pkg;
2. Gestionarea conceptelor
pachetului
Apelarea subprogramelor pachetului
 Dupa ce pachetul este stocat in baza de date,
puteti apela subprogramele stocate in acelasi
pachet sau in alte pachete.
Specify the subprogram name subprogram;
Within the same You can fully qualify a subprogram within the same
package package, but this is optional
package_name.subprogram
Fully qualify the (public) subprogram with its
External to the
package name
package package_name.subprogram
Care dintre urmatoarele apeluri realizate din
afara pachetului sal_pkg este valida (presupunand
fie ca apelantul detine pachetul, fie are privilegiul
EXECUTE asupra pachetului).

DECLARE
v_bool BOOLEAN;
v_number NUMBER;

BEGIN
a) sal_pkg.update_sal(100,25000);
b) update_sal(100,25000);
c) v_bool := sal_pkg.validate_raise(24000,25000);
d) v_number := sal_pkg.g_max_sal_raise;
e) v_number := sal_pkg.v_old_sal;
END;
2. Gestionarea conceptelor
pachetului
Stergerea pachetelor

 Pentru a sterge intreg pachetul, specificatia si


corpul se foloseste sintaxa:

DROP PACKAGE package_name;

 Pentru a sterge doar corpul pachetului, se


foloseste urmatoarea sintaxa:
DROP PACKAGE BODY package_name;
 Nu se poate elimina doar specificatia pachetului
2. Gestionarea conceptelor
pachetului
Vizualizarea pachetelor in Data Dictionary
Codul sursa pentru pachetele PL/SQL este
mentinut si este vizibil prin tabelele
USER_SOURCE si ALL_SOURCE in Data
Dictionary.

 Pentru a vizualiza specificatia pachetului se


foloseste:
SELECT text
FROM user_source
WHERE name = 'sal_PKG' AND type = 'PACKAGE'
ORDER BY line;
2. Gestionarea conceptelor
pachetului
 Pentru a vizualiza corpul pachetului se
foloseste:

SELECT text
FROM user_source
WHERE name = 'sal_PKG' AND type =
'PACKAGE BODY'
ORDER BY line;
Cum folosim USING_ERRORS?
 Atunci cand un subprogram PL/SQL esueaza
la compilare, Application Express afiseaza
numarul de eroare si textul mesajului:
2. Gestionarea conceptelor
pachetului
Pentru a vedea toate erorile (nu doar prima),
folositi un tabel din dictionarul USER_ERRORS:

CREATE OR REPLACE PROCEDURE


bad_proc
IS
BEGIN
error_1;
error_2;
END;
2. Gestionarea conceptelor
pachetului

SELECT sequence || '. Line: ' || line


"Where", text "Error Message"
FROM USER_ERRORS
WHERE name = 'BAD_PROC' AND type
= 'PROCEDURE'
ORDER BY sequence;
Codul anterior produce urmatoarea iesire:
USER_ERRORS nu indica codul sursa. Dar il putem
adauga la USER_SOURCE astfel:

SELECT e.sequence || '. Line: ' || e.line


"Where", s.text "Source Code", e.text
"Error Message"
FROM USER_ERRORS e, USER_SOURCE s
WHERE e.name = s.name AND e.type =
s.type
AND e.line = s.line
AND e.name = 'BAD_PROC' and e.type =
'PROCEDURE'
ORDER BY e.sequence;
Codul anterior produce urmatoarea iesire:
Reguli pentru scrierea pachetelor

 Construiti pachete pentru o utilizare generala


 Creati specificatia pachetului inainte de crearea
corpului
 Specificatia pachetului ar trebui sa contina acei
constructori care doriti sa fie publici/globali
 Recompilati doar corpul pachetului, daca este
posibil, deoarece schimbarile din specificatia
pachetului necesita recompilarea tuturor
programelor care apeleaza pachetul
 Specificatia pachetului ar trebui sa contina, pe cat
posibil, cat mai putini constructori.
Avantajele folosirii pachetelor

1. Modularizarea – incapsularea relatiilor


dintre constructori

2. O intretinere mai usoara – pastrarea la un


loc a elementelor legate

3. Proiectarea cu mai mare usurinta a


aplicatiilor – codarea si compilarea separata a
specificatiei si corpului pachetului
Avantajele folosirii pachetelor

4. Ascunderea informatiei:
◦ Doar declaratiile din specificatia pachetului
sunt vizibile si accesibile aplicatiilor
◦ Constructorii privati din corpul pachetului
sunt ascunsi si inaccesibili
◦ Toate codurile sunt ascunse in corpul
pachetului

5. O functionalitate suplimentara – se
pastreaza variabilele si cursorii
Avantajele folosirii pachetelor

6. Imbunatatirea performantelor:
◦ Intregul pachet este incarcat in memorie
atunci cand pachetul este referit prima data
◦ Exista o singura copie in memorie pentru
toti utilizatorii
◦ Se simplifica dependent ierarhia

7. Supraincarcarea – mai multe subprograme


au acelasi nume
Cuprins
Pachete în PL/SQL

1. Crearea pachetelor
1.1. Specificatia pachetului
1.2. Corpul pachetului
2. Gestionarea conceptelor pachetului
3. Concepte avansate despre pachete
3. Concepte avansate despre pachete
Supraincarcarea subprogramelor
 Termenul de supraincarcare in PL/SQL ne permite sa
dezvoltam doua sau mai multe subprograme in
pachete care au acelasi nume.
 Supraincarcarea este utila atunci cand vreti ca un
subprogram sa accepte o multime de parametri
asemanatori, dar care au tipuri de date diferite.
 De exemplu, functia TO_CHAR are mai multe
modalitati de a fi apelata, permitand convertirea unui
numar sau a unei date calendaristice intr-un sir de
caractere.
Supraincarcarea in PL/SQL
 Ne permite sa cream doua sau mai multe subprograme
cu acelasi nume, in acelasi pachet
 Ne permite sa construim modalitati flexibile sa apelam
aceleasi subprograme cu date diferite
 Face ca lucrurile sa fie mai usoare pentru dezvoltatorul
de aplicatie, care trebuie sa-si aminteasca doar un nume
de subprogram
 Regula de baza este ca puteti folosi acelasi nume pentru
subprograme diferite atata timp cat parametrii lor formali
difera ca numar, ordine, categorie sau tip de date.
Observatie:
 Supraincarcarea poate fi aplicata doar subprogramelor in
pachete, dar nu subprogramelor de sine statatoare.
Supraincarcarea in PL/SQL(continuare)

 Luati in considerare supraincarcarea atunci cand


sensul a doua sau mai multe subprograme este
asemanator, dar tipul sau numarul parametrilor folositi
variaza.
 Supraincarcarea poate oferi modalitati alternative
pentru a gasi diferite date cu diferite criterii de
cautare.
 De exemplu, poate doriti sa gasiti un angajat dupa
id-ul angajatului sau dupa id-ul job-ului sau data
angajarii.
 Scopul este acelasi, dar difera parametrii sau
criteriul de cautare.
3. Concepte avansate despre pachete
CREATE OR REPLACE PACKAGE
emp_pkg IS
PROCEDURE find_emp
(p_empno IN NUMBER, p_last_name OUT
VARCHAR2);
PROCEDURE find_emp
(p_job_id IN VARCHAR2, p_last_name
OUT VARCHAR2);
PROCEDURE find_emp
(p_hiredate IN DATE, p_last_name OUT
VARCHAR2);
END emp_pkg;
Specificatia pachetului emp_pkg contine o
procedura supraincarcata numita
find_emp.
Argumentele de intrare ale celor trei
declaratii au tipuri de date din categorii
diferite.
Care din declaratii se executa in urma
apelului de mai jos?

DECLARE v_last_name VARCHAR2(30);


BEGIN
emp_pkg.find_emp('IT_PROG',
v_last_name);
END;
Restrictiile supraincarcarilor

Nu se pot supraincarca:

1. Doua subprograme daca parametrii lor formali


difera doar prin tipul lor si tipurile de date sunt
in aceeasi categorie (NUMBER si INTEGER
apartin aceleiasi categorii; VARCHAR2 si CHAR
apartin aceleiasi categorii).
Restrictiile supraincarcarilor(continuare)

2. Doua functii care difera doar in tipul de date al


rezultatului, chiar daca tipurile respective fac
parte din categorii diferite.

3. De asemenea, aceste restrictii se aplica daca


numele parametrilor sunt aceleasi. Daca folositi
nume diferite pentru parametri, atunci puteti
apela subprogramele folosind notatia denumita
pentru subprograme.
3. Concepte avansate despre pachete

CREATE PACKAGE sample_pack IS

PROCEDURE sample_proc
(p_char_param IN CHAR);

PROCEDURE sample_proc
(p_varchar_param IN VARCHAR2);

END sample_pack;
3. Concepte avansate despre pachete
 Acum puteti apela o procedura folosind notatia
pozitionala.
BEGIN
sample_pack.sample_proc('Smith');
END;
 Aceasta esueaza deoarece ‘Smith’ poate fi atat
CHAR sau VARCHAR2. Dar urmatorul apel va
avea success:
BEGIN
sample_pack.sample_proc(p_char_param
=>'Smith');
END;
3. Concepte avansate despre pachete
 In urmatorul exemplu specificatia pachetului
dept_pkg contine o procedura supraincarcata
numita add_department.

 Prima declaratie are trei parametri care sunt


folositi pentru a oferi date pentru o noua
inregistrare a departamentului inserata in tabela
department.
 A doua declaratie are doi parametri deoarece
aceasta versiune genereaza intern id-ul
departamentului printr-o secventa Oracle.
CREATE OR REPLACE PACKAGE BODY dept_pkg IS
PROCEDURE add_department (
p_deptno NUMBER,
p_name VARCHAR2:='unknown',
p_loc NUMBER:=1700) IS
BEGIN
INSERT INTO dept (deptno, dname, loc)
VALUES (p_deptno, p_name, p_loc);
END add_department;

PROCEDURE add_department (
p_name VARCHAR2:='unknown',
p_loc NUMBER:=1700) IS
BEGIN
INSERT INTO dept (deptno, dname, loc)
VALUES (dept_seq.NEXTVAL, p_name, p_loc);
END add_department;

END dept_pkg;
 Daca apelati add_department cu un id de
departament furnizat explicit, atunci PL/SQL
foloseste prima versiune a procedurii.
 Fie urmatorul exemplu:
BEGIN
dept_pkg.add_department(980,'Education',2
500);
END;
SELECT *
FROM dept
WHERE deptno = 980;
deptno dname mgr loc
980 Education - 2500
Daca apelati add_department fara nici un
id de departament, atunci PL/SQL foloseste
a doua versiune.
BEGIN
dept_pkg.add_department ('Training',
2500);
END;
SELECT *
FROM dept
WHERE dname = 'Training';

deptno dname mgr loc


290 Training - 2500
Supraincarcarea si pachetul STANDARD

 Un pachet numit STANDARD defineste mediul


PL/SQL si functiile built-in.
 Cele mai multe functii built-in sunt supraincarcate.
 Ati studiat functia TO_CHAR ca exemplu. Alt
exemplu este functia UPPER:

FUNCTION UPPER (ch VARCHAR2)


RETURN VARCHAR2;
FUNCTION UPPER (ch CLOB) RETURN
CLOB;
 Subprogramele pachetului STANDARD nu se
prefixeaza cu numele pachetului.
Supraincarcarea si pachetul STANDARD

 Ce este intampla daca va creati propria functie


cu acelasi nume ca o functie din pachetul
standard?

 De exemplu va creati propria functie UPPER.

 Apoi o apelati ca UPPER(argument).

 Care dintre ele se executa?


Supraincarcarea si pachetul STANDARD

Raspuns:
 Chiar daca functia este in schema voastra, se va
executa functia STANDARD built-in.
 Pentru a apela functia proprie, este necesar sa
o prefixati cu numele schemei voastre.

BEGIN
v_return_value := your-schema-
name.UPPER(argument);
END;
Întrebări?

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