Documente Academic
Documente Profesional
Documente Cultură
date
#1 PL/SQL
Concepte generale
Adrian Runceanu
www.runceanu.ro/adrian
2022
copyright@www.adrian.runceanu.ro
Câteva precizări
Structura cursului
Câteva precizări
Procentaje evaluare Forme de examinare:
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
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.
Tehnici de programare cu
baze de date
Concepte generale
6
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
3. baza de date
copyright@www.adrian.runceanu.ro
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.
1. Modelul client-server
Aplicaţia logică este scindată între client
şi server.
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
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
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:
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
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
Î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
Cuprins
2.http://www.oracle.com/webfolder/technetwork/tutorials/
obe/db/devdays2012/apexp1_lab/apexp1_lab.html
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
Un bloc anonim
PL/SQL se compune
din sectiuni si are
sintaxa următoare:
Cuprins
3. Refolosire
copyright@www.adrian.runceanu.ro
Variabilele sunt:
Declarate si initializate in partea declarativa
Folosite, si li se atribuite valori in partea
executabila
Declararea variabilelor
Initializarea variabilelor
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
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
Cuprins
3.1. Identificatorii
3.1. Identificatorii
Proprietatile unui identificator:
3.1. Identificatorii
Exemple de identificatori corecti
First_Name LastName address_1
ID# Total_$ primary_department_contact
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:
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
v_prenume := 'Ion';
v_grupa := '134A';
v_data_astazi := '13-OCT-2015';
copyright@www.adrian.runceanu.ro
3.5. Comentarii
3.5. Comentarii
copyright@www.adrian.runceanu.ro
Cuprins
Nu au componente interne
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
Book (CLOB)
Photo(BLOB)
Movie (BFILE)
NCLOB
copyright@www.adrian.runceanu.ro
Cuprins
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
DECLARE
v_orderdate DATE := SYSDATE + 7;
v_natl_holiday DATE;
v_web_sign_on_date TIMESTAMP;
copyright@www.adrian.runceanu.ro
DECLARE
v_valid BOOLEAN NOT NULL := TRUE;
v_is_found BOOLEAN := FALSE;
v_underage BOOLEAN;
copyright@www.adrian.runceanu.ro
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
Î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
2
copyright@www.adrian.runceanu.ro
Cuprins
4
copyright@www.adrian.runceanu.ro
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
7
copyright@www.adrian.runceanu.ro
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
v_capitol_name:= UPPER(v_capitol_name);
v_emp_name:=v_first_name||'
'||v_last_name;
10
copyright@www.adrian.runceanu.ro
11
copyright@www.adrian.runceanu.ro
DECLARE
v_my_num BINARY_INTEGER :=-56664;
BEGIN
DBMS_OUTPUT.PUT_LINE(SIGN(v_my
_num));
END;
12
copyright@www.adrian.runceanu.ro
14
copyright@www.adrian.runceanu.ro
16
copyright@www.adrian.runceanu.ro
18
copyright@www.adrian.runceanu.ro
Cuprins
19
copyright@www.adrian.runceanu.ro
20
copyright@www.adrian.runceanu.ro
1. Conversii implicite
21
copyright@www.adrian.runceanu.ro
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
Valid? Statement
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
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
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
36
copyright@www.adrian.runceanu.ro
37
copyright@www.adrian.runceanu.ro
40
copyright@www.adrian.runceanu.ro
Cuprins
41
copyright@www.adrian.runceanu.ro
42
copyright@www.adrian.runceanu.ro
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
47
copyright@www.adrian.runceanu.ro
48
copyright@www.adrian.runceanu.ro
51
copyright@www.adrian.runceanu.ro
Se afiseaza
data de nastere
corecta?
56
copyright@www.adrian.runceanu.ro
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='Dec-12-2002';
58
copyright@www.adrian.runceanu.ro
<<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
60
copyright@www.adrian.runceanu.ro
Statement processed.
61
copyright@www.adrian.runceanu.ro
Cuprins
7. Domeniul de aplicare a
exceptiilor in blocurile imbricate
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
Î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
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).
10
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
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
15
copyright@www.adrian.runceanu.ro
17
copyright@www.adrian.runceanu.ro
18
copyright@www.adrian.runceanu.ro
Valoarea
NULL
preda
controlul pe
ramura
ELSE
19
copyright@www.adrian.runceanu.ro
20
copyright@www.adrian.runceanu.ro
21
copyright@www.adrian.runceanu.ro
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
25
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
28
copyright@www.adrian.runceanu.ro
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
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
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
1) Expresiile CASE:
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:
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
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.
45
copyright@www.adrian.runceanu.ro
3.1.Instructiunea LOOP
Basic LOOP (structura repetitiva de baza)
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
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
52
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.
3.2.Instructiunea WHILE
Sintaxa
56
copyright@www.adrian.runceanu.ro
3.2.Instructiunea WHILE
Conditia este o variabila sau o expresie
booleana (TRUE, FALSE sau NULL).
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
60
copyright@www.adrian.runceanu.ro
3.3.Instructiunea FOR
Sintaxa
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
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
Î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
3
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
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
…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
12
copyright@www.adrian.runceanu.ro
16
copyright@www.adrian.runceanu.ro
19
copyright@www.adrian.runceanu.ro
Cursor explicit:
1. Deschiderea cursorului
3. Închiderea cursorului
21
copyright@www.adrian.runceanu.ro
24
copyright@www.adrian.runceanu.ro
Cursor explicit:
1. Deschiderea cursorului
3. Închiderea cursorului
28
copyright@www.adrian.runceanu.ro
Cursor explicit:
1. Deschiderea cursorului
3. Închiderea cursorului
31
copyright@www.adrian.runceanu.ro
32
copyright@www.adrian.runceanu.ro
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
Cursor explicit:
1. Deschiderea cursorului
3. Închiderea cursorului
37
copyright@www.adrian.runceanu.ro
4. Inchiderea cursorilor
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
42
copyright@www.adrian.runceanu.ro
Cursori în PL/SQL
43
copyright@www.adrian.runceanu.ro
3. FOLOSIREA ATRIBUTELOR
CURSORILOR EXPLICITI
44
copyright@www.adrian.runceanu.ro
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;
…
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
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
51
copyright@www.adrian.runceanu.ro
52
copyright@www.adrian.runceanu.ro
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
55
copyright@www.adrian.runceanu.ro
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
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
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
3
copyright@www.adrian.runceanu.ro
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
10
copyright@www.adrian.runceanu.ro
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
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;
14
copyright@www.adrian.runceanu.ro
15
copyright@www.adrian.runceanu.ro
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
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
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
Sintaxa
OPEN cursor_name(parameter_value,...);
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
29
copyright@www.adrian.runceanu.ro
30
copyright@www.adrian.runceanu.ro
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
33
copyright@www.adrian.runceanu.ro
34
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
37
copyright@www.adrian.runceanu.ro
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
40
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
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
50
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;
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
57
copyright@www.adrian.runceanu.ro
58
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;
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
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.
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
Î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
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
6
copyright@www.adrian.runceanu.ro
1. Manipularea excepţiilor
1. Manipularea excepţiilor
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
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
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;
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
EXCEPTION
WHEN exception1 [OR exception2. . .]
THEN
Instructiune1;
Instructiune2;
…
[WHEN OTHERS THEN
Instructiune1;
Instructiune2;
…]
22
copyright@www.adrian.runceanu.ro
In cadrul sintaxei:
EXCEPTION
WHEN NO_DATA_FOUND THEN
Instructiune1;
…
WHEN TOO_MANY_ROWS THEN
Instructiune2;
…
WHEN OTHERS THEN
Instructiune3;
26
copyright@www.adrian.runceanu.ro
27
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
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
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
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
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
47
copyright@www.adrian.runceanu.ro
48
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
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
55
copyright@www.adrian.runceanu.ro
57
copyright@www.adrian.runceanu.ro
58
copyright@www.adrian.runceanu.ro
59
copyright@www.adrian.runceanu.ro
e_invalid_department EXCEPTION;
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
65
copyright@www.adrian.runceanu.ro
Sintaxa
RAISE_APPLICATION_ERROR
error_number,(message[, {TRUE |
FALSE}]);
67
copyright@www.adrian.runceanu.ro
68
copyright@www.adrian.runceanu.ro
Procedura RAISE_APPLICATION_ERROR se
poate folosi in doua locuri diferite:
1. Sectiunea executabila
69
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
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
3
copyright@www.adrian.runceanu.ro
RECAPITULARE
4
copyright@www.adrian.runceanu.ro
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
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
11
copyright@www.adrian.runceanu.ro
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
15
copyright@www.adrian.runceanu.ro
18
copyright@www.adrian.runceanu.ro
20
copyright@www.adrian.runceanu.ro
21
copyright@www.adrian.runceanu.ro
Cuprins
22
copyright@www.adrian.runceanu.ro
2. Proceduri
Crearea procedurilor
23
copyright@www.adrian.runceanu.ro
2. Proceduri
1. Proceduri
2. Functii
24
copyright@www.adrian.runceanu.ro
25
Diferenta dintre blocuri anonime si subprograme
copyright@www.adrian.runceanu.ro
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)
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
4. Integritatea datelor:
Actiunile pot fi grupate intr-un bloc si sunt
executate impreuna sau deloc.
31
copyright@www.adrian.runceanu.ro
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
procedure_body;
35
copyright@www.adrian.runceanu.ro
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.
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
Observatie:
Nu puteti apela o procedura din
interiorul unei instructiuni SQL cum ar fi
SELECT.
41
copyright@www.adrian.runceanu.ro
43
copyright@www.adrian.runceanu.ro
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
46
copyright@www.adrian.runceanu.ro
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
49
copyright@www.adrian.runceanu.ro
50
copyright@www.adrian.runceanu.ro
51
copyright@www.adrian.runceanu.ro
53
copyright@www.adrian.runceanu.ro
54
copyright@www.adrian.runceanu.ro
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
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
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
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
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
4
copyright@www.adrian.runceanu.ro
5
copyright@www.adrian.runceanu.ro
6
copyright@www.adrian.runceanu.ro
Tipul implicit 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
9
copyright@www.adrian.runceanu.ro
10
copyright@www.adrian.runceanu.ro
12
copyright@www.adrian.runceanu.ro
13
copyright@www.adrian.runceanu.ro
14
copyright@www.adrian.runceanu.ro
15
copyright@www.adrian.runceanu.ro
17
copyright@www.adrian.runceanu.ro
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'
19
copyright@www.adrian.runceanu.ro
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
21
copyright@www.adrian.runceanu.ro
22
copyright@www.adrian.runceanu.ro
Exemple:
23
copyright@www.adrian.runceanu.ro
24
copyright@www.adrian.runceanu.ro
25
copyright@www.adrian.runceanu.ro
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
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
29
copyright@www.adrian.runceanu.ro
30
copyright@www.adrian.runceanu.ro
1. add_dept;
31
copyright@www.adrian.runceanu.ro
33
copyright@www.adrian.runceanu.ro
Subprograme locale
Atunci cand o procedura apeleaza alta procedura,
in mod normal le cream separat.
34
copyright@www.adrian.runceanu.ro
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. Crearea funcţiilor
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
1. Crearea funcţiilor
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
... DBMS_OUTPUT.PUT_LINE(get_sal(100));
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
...
DBMS_OUTPUT.PUT_LINE(USER);
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
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
Caracteristici proceduri
Caracteristici functii
Functiile se pot folosi atunci cand dorim sa
transmitem o singura valoare mediului apelant.
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
27
copyright@www.adrian.runceanu.ro
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
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
Exemplu:
SELECT empno, tax(sal)
FROM emp;
SELECT empno, tax(p_value => sal)
FROM emp;
36
copyright@www.adrian.runceanu.ro
Exemplu 2
Urmatoarea functie interogheaza tabela
emp:
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:
3. Modificarea şi suprimarea
subprogramelor PL/SQL
Ca şi în cazul tabelelor, funcţiile şi
procedurile pot fi suprimate cu ajutorul
comenzii DROP.
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
43
copyright@www.adrian.runceanu.ro
4. Module overload
4. Module overload
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.
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. 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
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:
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
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)
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:
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:
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.
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
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
#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
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.
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
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
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)
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
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:
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
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)
Nu se pot supraincarca:
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.
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';
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?