proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea...

65
Proiectarea bazelor de date #6 Adrian Runceanu www.runceanu.ro/adrian 2016 PL/SQL Cursori în PL/SQL (partea II-a)

Transcript of proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea...

Page 1: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Proiectarea bazelor de date

#6

Adrian Runceanuwww.runceanu.ro/adrian

2016

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

Page 2: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Curs 6

Cursori în PL/SQL(continuare)

228.10.2018

Proiectarea bazelor de date

Page 3: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor

2. Cursori cu parametri

3. Folosirea cursorilor pentru

actualizari

4. Folosirea cursorilor multipli

28.10.2018Proiectarea bazelor de date 3

Page 4: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 4

Page 5: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Sintaxa

record name – numele unei inregistrari

declarate implicit (cursor_name%ROWTYPE)

cursor_name – identificator PL/SQL pentru un

cursor declarat anterior

28.10.2018Proiectarea bazelor de date 5

FOR record_name IN cursor_name

LOOP

Instructiune1;

Instructiune2;

END LOOP;

Page 6: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 6

Page 7: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 7

Page 8: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 8

Page 9: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 9

Page 10: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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

28.10.2018Proiectarea bazelor de date 10

Page 11: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;28.10.2018

Proiectarea bazelor de date 11

Page 12: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 12

Page 13: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 13

Page 14: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 14

Page 15: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 15

Page 16: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 16

Page 17: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 17

Page 18: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 18

Page 19: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor

2. Cursori cu parametri

3. Folosirea cursorilor pentru

actualizari

4. Folosirea cursorilor multipli

28.10.2018Proiectarea bazelor de date 19

Page 20: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 20

Page 21: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

DECLARE

CURSOR c_country (p_region_id NUMBER) IS

SELECT country_name, NATIONAL_HOLIDAY_DATE

FROM wf_countries

WHERE region_id = p_region_id;

v_country_record c_country%ROWTYPE;

BEGIN

OPEN c_country(5);

LOOP

FETCH c_country INTO v_country_record;

EXIT WHEN c_country%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_country_record.country_na

me || ' ' || v_country_record. NATIONAL_HOLIDAY_DATE);

END LOOP;

CLOSE c_country;

END;

28.10.2018Proiectarea bazelor de date 21

Page 22: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 22

Page 23: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Sintaxa

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

28.10.2018Proiectarea bazelor de date 23

CURSOR cursor_name

[( parameter_name datatype, ...)]

IS

select_statement;

Page 24: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Deschiderea cursorilor cu parametri

Sintaxa

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.

28.10.2018Proiectarea bazelor de date 24

OPEN cursor_name(parameter_value,...);

Page 25: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Exemplu 1 – cursor deschis de mai multe ori

DECLARE

CURSOR c_country (p_region_id NUMBER) IS

SELECT country_id, country_name

FROM wf_countries

WHERE region_id = p_region_id;

v_country_record c_country%ROWTYPE;

BEGIN

OPEN c_country (5);

CLOSE c_country;

OPEN c_country (145);

28.10.2018Proiectarea bazelor de date 25

Page 26: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 26

Exemplu 2

Page 27: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 27

Page 28: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Cursori cu parametri multipli

Exemplu 1- cursor cu doi parametri

DECLARE

CURSOR countrycursor2 (p_region_id NUMBER,

p_population NUMBER) IS

SELECT country_id, country_name, population

FROM wf_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.country_name||' '||

v_country_record.population);

END LOOP;

END;

28.10.2018Proiectarea bazelor de date 28

Page 29: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Exemplu 2 – codul preia toti programatorii IT care

castiga mai mult de 10000$

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('IT_PROG',

10000)

LOOP

DBMS_OUTPUT.PUT_LINE(v_emp_record.empno

||' ' || v_emp_record.ename);

END LOOP;

END;28.10.2018

Proiectarea bazelor de date 29

Page 30: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 30

Page 31: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor

2. Cursori cu parametri

3. Folosirea cursorilor pentru

actualizari

4. Folosirea cursorilor multipli

28.10.2018Proiectarea bazelor de date 31

Page 32: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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

28.10.2018Proiectarea bazelor de date 32

Page 33: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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…

28.10.2018Proiectarea bazelor de date 33

Page 34: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Sintaxa

28.10.2018Proiectarea bazelor de date 34

CURSOR cursor_name IS

SELECT ... FROM ...

FOR UPDATE [OF column_reference

n][NOWAIT | WAIT ];

Page 35: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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

28.10.2018Proiectarea bazelor de date 35

Page 36: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 36

Page 37: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Exemplu

DECLARE

CURSOR emp_cursor IS

SELECT empno, ename

FROM emp

WHERE deptno = 80 FOR UPDATE

NOWAIT;

28.10.2018Proiectarea bazelor de date 37

Page 38: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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

28.10.2018Proiectarea bazelor de date 38

Page 39: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

…28.10.2018Proiectarea bazelor de date 39

Page 40: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.28.10.2018

Proiectarea bazelor de date 40

Clauza WHERE CURRENT OF

Page 41: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Sintaxa

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).

28.10.2018Proiectarea bazelor de date 41

WHERE CURRENT OF cursor-name;

Page 42: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 42

3. Folosirea cursorilor pentru

actualizari

Page 43: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Exemple

1)

UPDATE EMP

SET salary = ...

WHERE CURRENT OF emp_cursor;

28.10.2018Proiectarea bazelor de date 43

Page 44: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 44

Exemple

Page 45: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 45

Page 46: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 46

Exemple

Page 47: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 47

Page 48: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Cursori în PL/SQL

1. LOOP-ul FOR pentru cursor

2. Cursori cu parametri

3. Folosirea cursorilor pentru

actualizari

4. Folosirea cursorilor multipli

28.10.2018Proiectarea bazelor de date 48

Page 49: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 49

Page 50: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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?

28.10.2018Proiectarea bazelor de date 50

Page 51: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 51

Page 52: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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

28.10.2018Proiectarea bazelor de date 52

Page 53: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 53

Page 54: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 54

Page 55: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 55

Page 56: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 56

Page 57: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 57

Page 58: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 58

Page 59: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Exemplu

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;28.10.2018

Proiectarea bazelor de date 59

Page 60: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

28.10.2018Proiectarea bazelor de date 60

Page 61: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 61

Page 62: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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.

28.10.2018Proiectarea bazelor de date 62

Page 63: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;

28.10.2018Proiectarea bazelor de date 63

Page 64: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

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;28.10.2018

Proiectarea bazelor de date 64

Page 65: proiectarea bazelor de date - runceanu.ro · LOOP-ul FOR pentru cursor S-a studiat utilizarea cursorilor expliciti cu folosirea instructiunilor DECLARE, OPEN si FETCH. Putem face

Întrebări?

28.10.2018Proiectarea bazelor de date 65