30 Haziran 2008 Pazartesi

Sql Server Cursor

Sql server üzerinde stored procedure, trigger tarzı az kişi tarafından bilinen bir diğer T-SQL, cursor. Az kişi tarafından bilinmesi de herhalde pek tavsiye edilmiyor olması. Tavsiye edilmiyor olmasının sebebi de Sql server ı resmen sömürüyor. Sql server kurulumu ile gelen ve sql serverın çalışması için gerekli veritabanlarından biri olan tempdb yi çok fazla kullanıyor bu da serverın doğal olarak yavaşlamasına sebep oluyor. Bu yüzden tavsiye edilen eğer yapacağınız işlemi store procedure, SQL cümlecikleri vs.. ile yapabiliyorsanız kesinlikle cursor kullanmayın(tabi okulda hocalarınız özel olarak cursor oluşturmanızı istemediyse :)).
Cursorleri herhandi bir programlama dilindeki diziler üzerinde gezmek gibi düşünebiliriz, gezme işlemi yaparken üzerinde olduğumuz kaydı da değiştirebiliriz. Bu diziyi de select cümlesiyle oluşturuyoruz.
Cursorun genel yapısı şu şekilde
  DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
[ TYPE_WARNING ]
FOR select_statement
[ FOR UPDATE [ OF column_name [ ,...n ] ] ]
Open cursor_name
.....
CLOSE cursor_name
DEALLOCATE cursor_name

Burada [a|b] arasındaki tanımlamaları istersek yazabiliriz yazarsak da sadece a veya b yazabiliriz. Her ikisini de yazarsanız hata alırsınız.
Tabi yazmazsak sql server bizim yerimize default olan değerleri koyacaktır. O yüzden cursorden tam olarak faydalanamayabiliriz.
Ben burada bir kaç tanesinin ne olduğundan bahsedeceğim bunlar önemli olanlar diğerlerine buradan bakabilirsiniz
Bu arada cursorde çok önemli bir ifade FETCH vardır bu kendisinden sonra gelen ifadeyle nereye dallanılacağını belirler.
LOCAL :Cursorun local olarak tanımlanması demek sadece kullanıldığı bağlantı içinde(stored procedure de tanımlanmışsa sadece o sp de kullanılabilir) görülecek demektir.Default olan değerdir eğer global veya local yazılmamışsa bu atanır
GLOBAL: Adından da anlaşılacağı üzere bütün bağlantılar tarafından görülebilen global bir cursor oluşturmuş oluruz.
FORWARD_ONLY: Bu bize cursor içinde sadece fetch next yapılacağını söyler. Tablonun baş satırından başlar sadece bir ileriye gidebiliriz.
SCROLL: Bu tanımlamayla bütün fetch işlemleri yapılabilir.
Diğerlerine de bakmanızı tavsiye ederim. Cursor üzerinde dolaşırken update yaptığınız zaman tablonuza yansıyıp yansımayacağı veya cursor açıldıktan sonra yeni veri girişi kabul edilmeyeceği gibi önemli şeyler var.
Tanımlanan fetch ler şunlardır.
FETCH FIRST: ilk kaydı fetch eder.
FETCH NEXT: bir sonraki kaydı fetch eder.
FETCH PRIOR: bir önceki satırı fetch eder.
FETCH LAST: en son satırı fetch eder.
FETCH ABSOLUTE n: n pozitif ise n. satır, n negatif ise sondan n. satır n=0 ise hiç bir satır fetch edilmez.
FETCH RELATIVE n: n pozitif ise en son fetch edilen satırdan n satır sonraki satırı fetch eder, n negatif ise fetch edilen satırdan n satır kadar önceki satırı fetch eder, n=0 ise fetch edilmez.
Bu arada fetch demek ilgili satırı alıp işlenir hale getirmek demek.
Bir örnekle bitireyim. Elimizde yazarlarla ilgili bir veritabanımız olsun. Girilen yazarın kitaplarını listeleyen bir stored procedure içinde cursor oluşturalım.

1. CREATE PROC yazarinKitaplari
2. @yazarAdi varchar(20)
3. AS
4. DECLARE @yazarKitap nvarchar(50)
5. DECLARE cursor_KitapListele CURSOR
6. LOCAL
7. SCROLL
8. FOR SELECT kitabi FROM yazar WHERE yazarAdi=@yazarAdi
9. OPEN cursor_KitapListele
10. FETCH LAST cursor_KitapListele INTO @yazarKitap
11. WHILE @@FETCH_STATUS=0
12. BEGIN
13. PRINT '@yazarAdi 'ın kitabı: @yazarKitap'
14. FETCH PRIOR cursor_KitapListele INTO @yazarKitap
15. END
16. CLOSE cursor_KitapListele
17. DEALLOCATE cursor_KitapListele

4. cursorden dönen kaydı bu parametreye geçireceğim eğer cursorde yazdığım select te 2 sütun dönseydi bana ona göre 2 değişken tanımlayıp fetch .. into dan sonra bu değişkenleri yazacaktım.
5. cursor bu şekilde tanımlanır.
8. cursorun üzerinde kayıt okuyacağı tablo bu select cümlesiyle geliyor.
9. cursor açılmalı, açılmazsa fetch işlemleri yapılmaz yani cursor bir işe yaramaz
10. son satırdan okumaya başladım kayıtları (fantazi yapıyom :)) okuduğum kaydı @yazarKitap değişkenine atıyorum.
11. @ fetch_status=0 demek fetch işleminin başarılı olması demek yani okunacak kayıt var.Okunacak kayıt varsa oku ve yazdır diyorum. fetch_status=-1 ise diğer kayda geçiş yapamamıştır yani satır sonu falan -2 ise öyle bir satır yok.
14. şu an son satırdayım bir önceki satıra gelip veriyi alıyorum bunu while ile en başa kadar yapıp kitapları yazdırıyorum.
16. açılan cursor mutlaka kapatılmalı ve
17. kullandığı kaynaklar bırakılmalı
Bu kadar yeter, bugün açıklanan veri tabanı dersinden geçmişim :D yoksa buraya küçük bir kitap yazardım valla. Bütünlemeye girecek arkadaşlara da kolay gelsin diyorum.

Hiç yorum yok: