You are on page 1of 8

PL/SQL

5 Kursori
Svaka SQL naredba ima individualni kursor povezan sa njom. Kursor predstavlja pokaziva na privatnu
SQL oblast koja uva informacije o odreenoj SELECT il DML naredbi.
Postoje dve vrste kursora:
Implicitni deklarie ih SUBP se za sve DML i PL/SQL SELECT naredbe.
Eksplicitni deklarisane i imenovane od programera, za upite koji vraaju vie redova.
Eksplicitni kursori omoguavaju procesiranje red po red za upite koji vraaju vie redova.
Sintaksa za deklarisanje:
CURSOR <ime_kursora> IS
<select_naredba>;
Pri deklaraciji kursora ne koristi se INTO opcija.
Primer 5.1
DECLARE
v_mbr radnik.mbr%TYPE;
v_prz radnik.prz%TYPE;
CURSOR radnik_cursor IS
SELECT mbr,prz
FROM radnik;
BEGIN
Null;
END;
/
Mogue je koristiti promenljive u kursoru, ali ih je neophodno prethodno deklarisati.
Da bi se pokrenuo upit i identifikovao aktivni skup treba otvoriti kursor.
OPEN <ime_kursora>;
Kursor se pozicionira na 1. red, a ako nema redova ne dolazi do greke.
Vraanje podataka iz kursora:|
FETCH <ime_kursora> INTO <promenljiva1>, <promenljiva2>... | <ime_sloga>;
Sintaksa:
...
OPEN <ime_kursora>;
LOOP
FETCH <ime_kursora> INTO <promenljive>
EXIT WHEN <uslov>;
...
-- Obrada dobijenih informacija
END;
...
Nakon zavretka rada sa kursorom, potrebno ga je zatvoriti.
Zatvaranje kursora
CLOSE <ime_kursora>;

Marija Raki-Skokovi 35
PL/SQL
Primer 5.2 Ispisati matini broj, ime i prezime za prvih deset radnika iz tabele RADNIK.
DECLARE
v_mbr radnik.mbr%TYPE;
v_prz radnik.prz%TYPE;
CURSOR radnik_cursor IS
SELECT mbr, prz FROM radnik;
BEGIN
OPEN radnik_cursor;
FOR i IN 1..10 LOOP
FETCH radnik_cursor INTO v_mbr, v_prz;
DBMS_OUTPUT.PUT_LINE('Mbr= '||v_mbr||' Prezime= '|| v_prz);
END LOOP;
CLOSE radnik_cursor;
END;
/
Pri obradi podataka na koje pokazuje kursor treba proveriti da li kursor sadri jo redova ili je stigao do
kraja, odnosno nema redova na koje pokazuje.
Atributi eksplicitih kursora:

Atribut Tip podatka koji vraa Vrednost

% ISOPEN Boolean TRUE ako je kursor otvoren

% NOTFOUND Boolean TRUE ako nema redova

% FOUND Boolean TRUE ima redova

% ROWCOUNT Number ukupan broj redova do sada

Atributi kursora imaju razliite vrednosti u zavisnosti od faze u kojoj se kursor nalazi. Tabela koja sledi
ilustruje razliita stanja i vrednosti atributa.

%FOUND %NOTFOUND %ISOPEN %ROWCOUNT

Pre OPEN exception exception FALSE exception

Posle OPEN NULL NULL TRUE 0

Pre 1.-og FETCH NULL NULL TRUE 0

Posle 1.-og FETCH TRUE FALSE TRUE 1

Pre sledeeg FETCH TRUE FALSE TRUE 1

Posle sledeeg FETCH TRUE FALSE TRUE N+1

Pre poslednjeg FETCH TRUE FALSE TRUE N+1

Posle poslednjeg FETCH FALSE TRUE TRUE N+1

Pre CLOSE FALSE TRUE TRUE N+1

Posle CLOSE exception exception FALSE exception

Marija Raki-Skokovi 36
PL/SQL
Primer 5.3
DECLARE
v_mbr radnik.mbr% TYPE;
v_prz radnik.prz% TYPE;
v_ime radnik.ime% TYPE;

CURSOR radnik_cursor IS
SELECT mbr, prz, ime
FROM radnik;
BEGIN
OPEN radnik_cursor;
LOOP
FETCH radnik_cursor INTO v_mbr, v_prz, v_ime;
EXIT WHEN radnik_cursor%ROWCOUNT>10 OR radnik_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(radnik_cursor%ROWCOUNT||'. '||'Mbr='||v_mbr||'
Prezime='|| v_prz||' Ime='|| v_ime);
END LOOP;
CLOSE radnik_cursor;
END;
/
Pre prvog FETCH, atribut %NOTFOUND ima vrednost NULL, pa ako se FETCH ne zavri uspeno
moemo upasti u beskonanu petlju u sluaju uslova radnik_cursor % NOTFOUND. Bolji uslov je
EXIT WHEN radnik_cursor%NOTFOUND OR (radnik_cursor%NOTFOUND IS NULL)

5.1 Kursori i slogovi


Mogue je deklarisati slog u koji e se uitavati podaci iz kursora upotrebom atributa %ROWTYPE.
Primer 5.4
DECLARE
CURSOR radnik_cursor IS
SELECT mbr, prz, ime
FROM radnik;

radnik_record radnik_cursor%ROWTYPE;
BEGIN
OPEN radnik_cursor;
LOOP
FETCH radnik_cursor INTO radnik_record;
EXIT WHEN radnik_cursor%NOTFOUND OR radnik_cursor%NOTFOUND IS NULL;
DBMS_OUTPUT.PUT_LINE('Mbr='|| radnik_record.mbr ||'
Prezime='||radnik_record.prz||' Ime='||radnik_record.ime);
END LOOP;
DBMS_OUTPUT.PUT_LINE('Ukupno ima '||RADNIK_CURSOR%rowcount||'
radnika.');
CLOSE radnik_cursor;
END;
/

Marija Raki-Skokovi 37
PL/SQL
5.2 Kursor FOR LOOP
Sintaksa
FOR <ime_sloga> IN <ime_kursora> LOOP
<blok naredbi>;
END LOOP;
Preica za obradu eksplicitnih kursora.
Prilikom izvrenja naredbe FOR LOOP dolazi do implicitnih operacija OPEN, FETCH i CLOSE nad
kursorom, kao i deklaracije sloga.
Primer 5.5
DECLARE
CURSOR radnik_cursor IS
SELECT prz, sodel
FROM radnik;
BEGIN
FOR radnik_record IN radnik_cursor LOOP
-- dolazi do implicitnog open, fetch

IF radnik_record.sodel = 2 THEN
DBMS_OUTPUT. PUT_LINE ('Radnik '|| radnik_record.prz ||' radi u
odeljenju za marketing');
END IF;
END LOOP; -- implicitno zatvara kursor
END;
/
Primer 5.6 Isto kao prethodni samo provera uslova u select naredbi.
DECLARE
CURSOR radnik_cursor IS
SELECT prz
FROM radnik
WHERE sodel=3;
BEGIN
FOR radnik_record IN radnik_cursor LOOP
DBMS_OUTPUT. PUT_LINE ('Radnik '|| radnik_record.prz ||' radi
u odeljenju za marketing');
END LOOP;
END;
/

Marija Raki-Skokovi 38
PL/SQL
5.3 Dinamiki kursor FOR LOOP
Kursor FOR LOOP, moe biti proiren tako da obuhvata podupite. Ovo znai da kursor nee biti
deklarisan u DECLARE sekciji, ve se implicitno kreira pri izvravanju podupita koji je vezan za njega.
Primer 5.7
BEGIN
FOR I IN (SELECT prz, naz, plt
FROM radnik r, radnomesto rm
WHERE sodel=1 and r.srm=rm.srm)
LOOP
DBMS_OUTPUT.PUT_LINE('Radnik '||I.prz||' koji radi na poslu '||I.naz||'
zaradjuje '||I.plt||' mesecno.');
END LOOP;
END;/

5.4 Kursori sa parametrima


Kursori mogu imati i parametre.
CURSOR <ime_kursora> <parametar1>,...
IS <select_naredba>;
Parametar:
<ime_parametra> IN <tip> := | DEFAULT <izraz>
Tip parametra je neki skalarni tip bez specifikacija veliine.
Korisno kad se isti kursor referencira vie puta u jednom bloku.
Kod otvaranja kursora moraju da se proslede i argumenti.
Mogue je otvarati kursor pomou promenljivih.
FOR LOOP kursor moe da prosleuje parametre.
Primer 5.8
DECLARE
CURSOR radnik_cur( p_sodel NUMBER) IS
SELECT mbr, prz
FROM RADNIK
WHERE sodel=p_sodel;

BEGIN
DBMS_OUTPUT. PUT_LINE ('Odeljenje 1');
FOR RADNIK_REC IN RADNIK_CUR(1) LOOP
DBMS_OUTPUT. PUT_LINE (radnik_cur%ROWCOUNT||'. '||'Radnik '||
RADNIK_REC.PRZ ||'. Id broj: '||RADNIK_REC.MBR);
END LOOP;
dbms_output.new_line;
DBMS_OUTPUT. PUT_LINE ('Odeljenje 2');
FOR RADNIK_REC IN RADNIK_CUR(2) lOOP
DBMS_OUTPUT. PUT_LINE (radnik_cur%ROWCOUNT||'. '||'Radnik '||
RADNIK_REC.PRZ ||'. Id broj: '||RADNIK_REC.MBR);
END LOOP;
END;
/

Marija Raki-Skokovi 39
PL/SQL
5.5 FOR UPDATE klauzula
Podatke u tabeli je mogue obrisati ili modifikovati upotrebom kursora. Da bi modifikacija ili brisanje
redova iz tabeli bilo mogue, potrebno je deklarisati kursor sa FOR UPDATE klauzulom. Naredbe
UPDATE ili DELETE u tom sluaju moraju sadrati WHERE CURRENT OF klauzulu.
Sintaksa:
CURSOR <ime_kursora> <parametar1>,...
IS <select_naredba>
FOR UPDATE OF <referenca_na_kolonu> NOWAIT;
Dolazi do zakljuavanja redova kada se kursor otvori.
NOWAIT vraa greku ako su redovi ve zakljuani u drugoj sesiji.
Potrebno je koristiti klauzulu WHERE CURRENT OF za referenciranje na red na koji kursor trenutno
pokazuje.
Sintaksa:
WHERE CURRENT OF ime_kursora
Primer 5.9 Poveati platu za 10% svima u odeljenju 3.
DECLARE
CURSOR plt_cursor IS
SELECT plt FROM radnik
WHERE sodel = 3
FOR UPDATE OF plt NOWAIT;
BEGIN
FOR radnik_record IN plt_cursor LOOP
UPDATE radnik
SET plt = radnik_record.plt * 1.1
WHERE CURRENT OF plt_cursor;
END LOOP;
COMMIT;
END;
/

5.6 Kursori sa pod upitima


Kursori mogu da koriste i pod upite.
Primer 5.10 Izlistati naziv, lokaciju, broj odeljenja i broj radnika u odeljenju za odeljenja u kojima radi
bar 5 radnika.
DECLARE
CURSOR odeljenje_cursor IS
SELECT t1.nazod, t1.lok, t1.sodel, t2.radnici
from odeljenje t1, (select sodel, count(*) as radnici FROM radnik GROUP BY
sodel) t2
where t2.radnici>=5 and t1.sodel=t2.sodel;
BEGIN
FOR odeljenje_record IN odeljenje_cursor LOOP
DBMS_OUTPUT.PUT_LINE('U odeljenju '||odeljenje_record.sodel||'
'||odeljenje_record.nazod||' na lokaciji '||odeljenje_record.lok||' radi
'||odeljenje_record.radnici||' radnika');
END LOOP;
END;
/

Marija Raki-Skokovi 40
PL/SQL
5.7 Primeri upotrebe kursora
Primer 5.11
Kreirati proceduru TOP_N koja u tabelu TOP_DOGS(mbr, plata) upisuje prvih N zaposlenih po zaradi,
gde je N parametar koji se prosleuje proceduri. U sluaju da ne postoji, prethodno kreirati tabelu
TOP_DOGS.
CREATE OR REPLACE PROCEDURE top_n(P_NUM IN NUMBER)
AS
v_mbr radnik.mbr%TYPE;
v_plt radnik.plt%TYPE;
CURSOR radnik_cursor IS
SELECT mbr, plt
FROM radnik
WHERE plt IS NOT NULL
ORDER BY plt DESC;
BEGIN
DELETE FROM top_dogs;
OPEN radnik_cursor;
LOOP
FETCH radnik_cursor INTO v_mbr, v_plt;
EXIT WHEN (RADNIK_CURSOR%ROWCOUNT > P_NUM) OR
radnik_cursor%NOTFOUND OR (radnik_cursor%NOTFOUND IS NULL);
INSERT INTO top_dogs (mbr, plata)
VALUES (v_mbr, v_plt);
END LOOP;
CLOSE radnik_cursor;
COMMIT;
END top_n;
/

Upisati prvih 5:

begin top_n(5);end;
Primer 5.12
Kreirati proceduru PrekoNorme koja kao ulazne parametre ima ifru radnog mesta i max iznos plate, a
treba da ispie sve radnike (ime i prezime) koji rade na tom radnom mestu, a imaju platu veu od
prosleene vrednosti, kao i koliko imaju vie. Ispis bi trebao biti poput:
Radnik Petar Petrovic ima platu vecu od norme za 1450
Primer 5.13
Napisati proceduru koja za prosleenu ifru radnog mesta (SRM) ispisuje podatke o radnicima koji rade
na tom radnom mestu i to na sledei nain:
a) Ako ima radnika :
Na radnom mestu <naziv radnog mesta> rade sledeci radnici:
<redni broj> <ime i prezime radnika> radi u odeljenju <naziv odeljenja>,
<lokacija odeljenja>
Ukupno radnika: <br.radnika>
Ispis sortirati po odeljenjima u kojima radnici rade.
b) Ako nema radnika na tom radnom mestu:
Na radnom mestu <naziv radnog mesta> ne radi ni jedan radnik.

Marija Raki-Skokovi 41
PL/SQL
Primer 5.14
Napisati proceduru pod nazivom PLATE, koja proverava kolika je plata radnika u odnosu na prosenu
platu u okviru odeljenja u kom radnik radi i generie ispis za sve radnike iz tabele RADNIK na sledei
nain:
Ako ima platu veu od prosene:
<prezime radnika> radi u odeljenju <naziv odeljenja> i ima platu vecu od prosecne

Ako ima platu manju od prosene:


<prezime radnika> radi u odeljenju <naziv odeljenja > i ima platu manju od prosecne

I inae
<prezime radnika> radi u odeljenju <naziv odeljenja > i ima prosecnu platu
Ispis sortirati rastue po nazivima odeljenja.

Marija Raki-Skokovi 42

You might also like