Professional Documents
Culture Documents
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:
Atributi kursora imaju razliite vrednosti u zavisnosti od faze u kojoj se kursor nalazi. Tabela koja sledi
ilustruje razliita stanja i vrednosti atributa.
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)
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;/
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;
/
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
I inae
<prezime radnika> radi u odeljenju <naziv odeljenja > i ima prosecnu platu
Ispis sortirati rastue po nazivima odeljenja.
Marija Raki-Skokovi 42