Vannak dolgok, amiket nem érdemes kliens oldalon erőltetni az adatmozgatás és sebesség miatt, hanem tárolt eljárásban megoldani. Előfordulhat olyan eset, amikor nem tudunk egy sima select vagy insert into ... (select...) utasítással feltölteni egy táblát, hanem végig kell a forrás táblát olvasni soronként. Erre való a cursor. Mutatok egy rövid példát és a benne rejlő buktatót is.
Van két táblánk, amiket az "azon" mezők értéke kapcsol össze. A Tabla1_azon értéke alapján kell a Tabla2_mezo értékét kivenni, feldolgozni. Figyeljük meg, hogy egy sorban nem egyeznek meg az azonosító mezők értékei
Tabla2 | Tabla1 | |
Tabla2_azon | Tabla2_mezo | Tabla1_azon |
Ertek1 | Mezo1 | Ertek1 |
Ertek2 | Mezo2 | Ertek3 |
Ertek4 | Mezo4 | Ertek4 |
declare done default 0;
declare v_azon integer;
declare valtozo integer;
declare cursor1 for select tabla1_azon from tabla1;
declare continue handler for not found set done = 1;
open cur1;
read_loop: loop
fetch cursor1 into v_azon;
if done then
leave read_loop;
end if;
if exists (select '' from tabla2 where tabla2_azon = v_azon) then
select tabla2_mezo into valtozo from tabla2 where tabla2_azon = v_azon;
end if;
-- valtozo tovabbi feldolgozasa
end loop;
close cur1;
A done változót a handler állítja be, ha nincs több olvasandó adat. Deklaráljuk a cursor-t, a handlert. Úgy hisszük, hogy ez akkor áll be, ha a cursor-nál elfogytak a sorok, vagyis végigolvastuk a Tabla1-et. Cursor nyitás, ciklus elejének beállítása, egyéb cirádák. A fetch beolvassa az into utáni változókba a következő sor mezőinek tartalmát. A mezők és változók számának, tipusának meg kell egyeznie. A ciklusból a fetch utáni if léptet ki.
Teoretikusan az "if exists" és az azt lezáró "end if" részt kommentezzük ki. Hivatalosan a Tabla2 megfelelő mező értékét visszakapjuk a valtozoban az azonosító mezők párosítása alapján.
És elkezdünk csalódni. Mert a mezo4 soha nem kerül be a valtozoba, pedig guvadt szemmel nézzük az azonosítók egyezését. Megvan a megoldás: bugos a mysql. A google is csak vonogatja a vállát, mindent a megadott példák szerint csináltunk.
Az igazi megoldás a következő: bár a handler-t rögtön a cursor után deklaráltuk, az nem akkor áll be, ha a cursor-nál elfogytak a beolvasandó sorok. Hanem ha valamit nem talál meg. Mint az állapota is mutassa - not found -. És mivel a handler hatóköre az egész tároltra kiterjed, nem csak a cursor-ra így a "select tabla2..." sornál billen be, mert a két azonosító egy helyen nem egyezik meg, vagyis not found.
Teoretikusan vegyük ki a kommenteket, és lőn. Csak azt a sort nem dolgozza fel a tárolt, ahol nem egyeznek az azonosítók.
Tehát egy tárolt eljárásban, ha cursor-t használunk, le kell kezelni minden hasonló ágat.