Lekcija: Kursori (Cursor) - Koncept, vrste i rad sa kursorima
Uvod
Do sada smo u radu sa SQL Server-om uglavnom koristili naredbe koje rade nad skupom podataka.
Na primer:
SELECT *
FROM Film;
Ovaj upit obrađuje sve redove odjednom.
SQL je napravljen tako da radi nad skupovima podataka, a ne nad pojedinačnim redovima.
Međutim, postoje situacije kada želimo da obradimo:
jedan po jedan red tabele
Na primer: ispis svakog filma pojedinačno, obrada svakog zaposlenog posebno, računanje različitih vrednosti za svaki red, izvršavanje posebnih pravila za svaki zapis.
Za takve situacije koriste se kursori.
1. Šta je kursor?
Kursor (Cursor) predstavlja objekat baze podataka koji omogućava:
prolazak kroz rezultate upita red po red
Možemo ga zamisliti kao pokazivač koji se kreće kroz rezultate SELECT upita.
Na primer:
Ako tabela ima:
| FilmID | Naziv |
|---|---|
| 1 | Titanik |
| 2 | Avatar |
| 3 | Matrix |
običan SELECT vraća sve redove odjednom.
Kursor prolazi:
-
Titanik
-
Avatar
-
Matrix
jedan po jedan red.
Zašto postoje kursori?
Ponekad obične SQL naredbe nisu dovoljne.
Na primer, ako želimo: za svaki film ispisati posebnu poruku, ili za svakog zaposlenog izvršiti različit obračun ili prolaziti kroz rezultate jedan po jedan. Tada koristimo kursor.
Napomena:
Kursori su sporiji od običnih SQL upita.
Zbog toga važi pravilo:
Ako problem može da se reši običnim SQL upitom, NE koristiti kursor.
Kursor koristiti samo kada je potrebna obrada:
red po red
2. Vrste kursora
Kursori se dele na:
1. Implicitne kursore
2. Eksplicitne kursore
2.1 Implicitni kursori
Implicitne kursore SQL Server koristi automatski.
Programer ih ne kreira direktno.
Na primer:
UPDATE Film
SET Naziv = 'Novi film'
WHERE FilmID = 1;
SQL Server interno prolazi kroz podatke.
Programer to ne vidi.
Zbog toga se kaže da SQL koristi implicitni kursor.
2.2 Eksplicitni kursori
Eksplicitni kursori su oni koje:
programer sam kreira
Koriste se kada želimo potpunu kontrolu nad prolaskom kroz podatke.
Kod njih sami određujemo: koji podaci se prolaze, kada počinje prolazak, kada se završava, šta se radi sa svakim redom.
3. Kako radi kursor?
Rad sa kursorom odvija se kroz više koraka.
Najlakše je zapamtiti sledeći redosled:
1. DECLARE
(kreiranje kursora)
2. OPEN
(pokretanje kursora)
3. FETCH
(preuzimanje reda)
4. WHILE
(prolazak kroz podatke)
5. CLOSE
(zatvaranje kursora)
6. DEALLOCATE
(oslobađanje memorije)
Ovo je veoma važno zapamtiti jer se skoro svaki kursor pravi po ovom modelu.
4. Kreiranje kursora
Kursor se kreira pomoću:
DECLARE naziv_kursora CURSOR FOR
SELECT ...
Primer:
DECLARE film_cursor CURSOR FOR
SELECT Naziv
FROM Film;
Ovde:
-
film_cursor→ naziv kursora -
SELECT Naziv FROM Film→ podaci kroz koje prolazimo
5. Otvaranje kursora
Nakon kreiranja, kursor mora da se pokrene.
Koristi se:
OPEN naziv_kursora;
Primer:
OPEN film_cursor;
6. FETCH – preuzimanje reda
FETCH uzima sledeći red iz kursora.
Sintaksa:
FETCH NEXT
FROM naziv_kursora
INTO promenljiva;
Primer:
DECLARE @naziv VARCHAR(100);
FETCH NEXT
FROM film_cursor
INTO @naziv;
Ovde:
-
uzima se sledeći red,
-
smešta se u promenljivu
@naziv.
7. @@FETCH_STATUS
SQL Server koristi sistemsku promenljivu:
@@FETCH_STATUS
Njena vrednost govori:
| Vrednost | Značenje |
|---|---|
| 0 | uspešno učitan red |
| -1 | nema više podataka |
| -2 | red ne postoji |
Najčešće proveravamo:
WHILE @@FETCH_STATUS = 0
što znači:
„dok postoje podaci“
8. Kompletan primer kursora
Prikaz svih naziva filmova.
DECLARE @naziv VARCHAR(100);
DECLARE film_cursor CURSOR FOR
SELECT Naziv
FROM Film;
OPEN film_cursor;
FETCH NEXT
FROM film_cursor
INTO @naziv;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @naziv;
FETCH NEXT
FROM film_cursor
INTO @naziv;
END
CLOSE film_cursor;
DEALLOCATE film_cursor;
Objašnjenje korak po korak
1. Kreira se promenljiva
DECLARE @naziv VARCHAR(100);
Čuva naziv filma.
2. Kreira se kursor
DECLARE film_cursor CURSOR FOR
SELECT Naziv
FROM Film;
3. Otvara se
OPEN film_cursor;
4. Učitava prvi red
FETCH NEXT
FROM film_cursor
INTO @naziv;
5. Petlja prolazi kroz sve redove
WHILE @@FETCH_STATUS = 0
6. Prikazuje podatke
PRINT @naziv;
7. Učitava sledeći red
Bez ovoga nastala bi beskonačna petlja.
8. Zatvara kursor
CLOSE film_cursor;
9. Oslobađa memoriju
DEALLOCATE film_cursor;
9. Primer – prolazak kroz glumce
DECLARE @ime VARCHAR(50);
DECLARE glumac_cursor CURSOR FOR
SELECT Ime
FROM Glumac;
OPEN glumac_cursor;
FETCH NEXT
FROM glumac_cursor
INTO @ime;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @ime;
FETCH NEXT
FROM glumac_cursor
INTO @ime;
END
CLOSE glumac_cursor;
DEALLOCATE glumac_cursor;
10. Kada koristiti kursor?
Koristiti kada:
treba prolaziti red po red
postoji složena poslovna logika
jedan SQL upit nije dovoljan
svaki red zahteva posebnu obradu
11. Kada NE koristiti kursor?
Ne koristiti kada može:
UPDATE Film
SET Cena = Cena * 1.10
Običan UPDATE je mnogo brži od kursora.
12. Najčešće greške
1. Zaboravljen OPEN
Pogrešno:
FETCH NEXT FROM film_cursor
Kursor nije otvoren.
2. Zaboravljen FETCH unutar petlje
Nastaje beskonačna petlja.
3. Zaboravljen CLOSE
Kursor ostaje aktivan.
4. Zaboravljen DEALLOCATE
Memorija nije oslobođena.
13. Razlika između implicitnog i eksplicitnog kursora
| Implicitni | Eksplicitni |
|---|---|
| SQL radi automatski | programer kreira |
| ne vidi se | vidi se u kodu |
| jednostavan | složeniji |
| koristi se interno | koristi se po potrebi |
Zadaci za vežbu
Zadatak 1 - Napraviti kursor koji prikazuje sve nazive žanrova.
Zadatak 2 - Napraviti kursor koji prolazi kroz prezimena glumaca.
Zadatak 3 - Objasniti razliku između implicitnog i eksplicitnog kursora.
Zadatak 4 - Objasniti zašto nije dobro koristiti kursor kada običan UPDATE rešava problem.
Zaključak
Kursor predstavlja alat za prolazak kroz podatke:
red po red
Najvažnije što treba zapamtiti:
Redosled rada:
DECLARE → OPEN → FETCH → WHILE → CLOSE → DEALLOCATE
Kursori su korisni, ali ih treba koristiti pažljivo jer mogu usporiti rad baze podataka. Uvek prvo proveriti da li problem može da se reši običnim SQL upitom.