Muazzez KONUKLU

Cuma, Şubat 02, 2007

SQL SERVER 2000'DE CURSOR (İMLEÇ) KULLANIMI

SQL SERVER 2000'de CURSOR (İmleÇ) KullanImI


Bilgisayar ile uğraşırken sürekli olarak bir yerlere bilgi girmemiz gerekir. Bilgi girişinde en çok muhatap olduğumuz yardımcımız imleç (cursor) tir. Bize bilgisayarın o an hangi alanla ilgilendiğini gösteren ( hatta şu an bile karşımda yanıp sönen ) imleç aynı mantıkla SQL Server üzerinde de tanımlanmıştır.

Cursor'lar (imleçler) SQL Server üzerinden döndürdüğümüz belli bir kayıt kümesi üzerinde satır satır işlem yapabilmemize olanak sağlayan veritabanı nesneleridir.
Satır bazında işlem yapmak aslında programlama ile uğraşanlar için sıradan işlerdendir. Bu tarz bir işlem için genel olarak aşağıdaki adımlar sırayla izlenir;

 Veritabanından veri yığını istemciye çekilir.
 Veri üzerinde, yüksek seviyeli programlama dilleri kullanılarak yazılmış kodlar sayesinde istenilen değişiklikler yapılır. Yüksek seviyeli dillerde sunulan döngü yapıları sayesinde her kaydı tek tek incelemek işten bile değildir.
 Elde edilen sonuç kümesi veritabanına gönderilir.
Bizim üzerinde duracağımız, ikinci yöntem ise aynı işlemleri veritabanı sunucumuz üzerinde yapmaktır.

İki farklı yöntemin de en uygun olduğu durumlar vardır. Örneğin satır bazında T-SQL ile yapamayacağınız karışık işlemleri istemci tarafında yüksek seviyeli bir dil ile yazacağınız kodlar ile kolaylıkla yapabilirsiniz. Ya da T-SQL ile kotarılabilecek satır bazında işlemleri, sunucuda cursor'ları (imleçleri) kullanarak halledebilir ve bu sayede ağ trafiğinin azalmasını sağlayabilirsiniz.

Yüksek seviyeli dillerde sağlanan döngü yapıları yerine sunucuda cursor'ları (imleçleri) kullanırız. Cursor'ların (imleçlerin) kullanım yerlerini örnekler üzerinde inceleyeceğiz. Örnekler için SQL Server 2000 ile gelen 'pubs' örnek veritabanını kullanacağız. İlk örneğimiz 'titles' tablosunda bulunan kitapların fiyatlarını güncellemek olacak.

İş planımıza göre;
 20$ altındaki fiyatlar için artış oranı %10
 20$ ve üzerindeki fiyatlar için artış oranı %5
olduğunu kabul edelim.

Bunun için aşağıdaki standart T-SQL ifadelerini kullanabilir;


UPDATE titles
SET price = price * (price * .1)
WHERE price <>
SET price = price * (price * .05)
WHERE price >= 20

Buradaki sorunu farkettiniz mi? Farkettiğinizi duyar gibiyim. Eğer kitap fiyatı 19.95$ ise ilk ifadede %10'luk artış uygulanacak, bu sayede 20$'ın üstüne çıktığı için ek olarak %5'lik bir artış daha uygulanacak ve istemediğimiz sonuçlar oluşacaktır.

Bu sorunu aşmak için satırları tek tek ele alıp onlar üzerinde işlem yapmak üzere cursor'ları (imleçleri) kullanacağız.

Temel bir cursor (imleç) ifadesi aşağıdaki gibi yazılır.

USE pubs GO DECLARE cr_fiyatlar CURSOR FOR
SELECT price FROM titles
OPEN cr_fiyatlar
FETCH NEXT FROM cr_fiyatlar
WHILE @@FETCH_STATUS = 0 FETCH NEXT
FROM cr_fiyatlar CLOSE cr_fiyatlar
DEALLOCATE cr_fiyatlar

Bu ifadeyi Query Analyzer'da çalıştırdığınızda alttaki şekilde görünene benzer bir sonuç listesi elde edersiniz.






İfadede kullanılan terimlere geçmeden önce, cursor (imleç) kullanmadan sadece SELECT ifadedesi ile aynı verileri elde etmeye çalışsaydık nasıl bir sonuç elde edecektik ona bakalım.
Alttaki Şekilde, cursor (imleçleri) kullanmadan, verileri aynı SELECT ifadesiyle ( SELECT price FROM titles ) seçtiğimizde aldığımız sonucu görüyorsunuz.



Aralarındaki farka dikkat çekmek istiyorum. Cursor (imleç) kullandığınız zaman birer satır içeren sonuç kümeleri döner. Fakat sadece SELECT ifadesi kullandığınızda tüm sonuçlar tek bir küme olarak döner.

Şimdi cursor (imleç) ifademizde kullandığımız terimleri incelersek:

DECLARE cr_fiyatlar CURSOR FOR

Bu ifade yeni bir cursor (imleç) tanımlamak için kullanılır. DECLARE ifadesinden sonra cursor'un (imlecin) adını belirtiriz.

Addan hemen sonra gelen CURSOR FOR ifadesinden sonra ise cursor'un (imlecin) hangi veriler için tanımlayacağımızı belirtiriz.
Örneğimizde ismi 'cr_fiyatlar' olan bir cursor (imleç)

SELECT price FROM titles

' SELECT price FROM titles ' ifadesi ile dönecek olan veri kümesi içinde çalışmak üzere tanımlanıyor. Bu ifade ile dönecek olan veri kümesi üzerinde, tanımladığımız cursor'u (imleci) kullanarak satır satır gezme imkanımız olacak.
Burda titles tablosundan price alani uzerinde satir satir gezmemiz saglanir.

Cursor'un tanımlanacağı veri kümesini tanımlayan SELECT ifadesi içinde, WHERE, GROUP BY ve ORDER BY gibi yardımcı T-SQL komutları da kullanılabilir.

OPEN

OPEN cr_fiyatlar
OPEN deyimi, belirtilen cursor (imleç) için bellekte yer ayırır ve ilk kullanım için gerekli ayarları yapar. Artık cursor (imleç) ilk kullanım için hazırdır.
FETCH
FETCH NEXT FROM cr_fiyatlar
FETCH NEXT deyimi tek bir kaydı alır ve cursor'a (imlece) yükler.
NEXT ifadesi yerine PRIOR (önceki), FIRST (ilki) ve LAST (sonuncusu) gibi ifadeler de kullanabiliriz.

@@FETCH_STATUS
WHILE @@FETCH_STATUS = 0 FETCH NEXT FROM cr_fiyatlar
Örneğimizde cursoru (imleci) WHILE döngüsü ile kontrol etttik. @@FETCH_STATUS ifadesi döngümüzün kontrol birimidir. FETCH ifadesinin sonucuna göre üç farklı değer alabilir.
Bunlar ;
 0: Bir önceki FETCH ifadesi başarılı
 -1: Bir önceki FETCH ifadesi hata ile karşılaştı
 -2: Son kayıt.
Örneğimizde WHILE @@FETCH_STATUS = 0 ifadesi ile hata olmadığı sürece bir sonraki kayıt elde edilir.

Bir cursor'un (imlecin) içine farklı bir cursor (imleç) yerleştirme şansınız da vardır. Alternatif olarak bir cursor (imleç), içinde cursor (imleç) bulunan bir stored procedure (saklı yordam) çağırabilir. Böyle bir durumda @@FETCH_STATUS değerine dikkat etmek gerekir. Çünkü bu fonksiyon döngü düzeyinde değil bağlantı düzeyinde kontrol yapar.
CLOSE

CLOSE cr_fiyatlar

Kayıtlar cursor'a (imlece) yüklendiğinde cursor lock (imleç kilidi) oluşur. Bu kilit, CLOSE ifadesine kadar serbest bırakılmaz. CLOSE ifadesinden sonra cursor (imleç) tekrar açılabilir. Kapatıp açınca cursor (imleç) hiçbir özelliğini kaybetmiş olmaz. Yani bellekten atılmış değildir. CLOSE ile kapatmaktaki amaç kilidi açmaktır.
DEALLOCATE
DEALLOCATE cr_fiyatlar

CLOSE ile cursor'un (imlecin) bellekten temizlenmediğini belirtmiştik. Cursor (imleç) ile işimiz tamamen bittiğinde cursor'u (imleci) kaldırmak için kullanılan bellek alanını boşaltmalı ve değişkenleri yok etmeliyiz. DEALLOCATE bu işlemleri tek seferde yapar. Bu işlemden sonra cursor (bellekten) bellekten kaldırılmıştır.

Cursorlar (imleçler) sayesinde veri kümeleri üzerinde değil, alışık olduğumuz yapısal sorgulamalara benzer şekilde satır satır işlem yapabiliriz. Bu beraberinde bir miktar performans kaybını beraberinde getirir. Ama bazı durumlarda bu, yapılacak karmaşık işlemlerin basitleşmesinden dolayı kabul edilebilir. Buraya kadar bir cursor'un (imlecin) genel olarak nasıl yazıldığını gördük. Şimdi yazımızın başında kurduğumuz senaryoyu gerçekleştirelim.
WHERE CURRENT OF

Yukarıdaki örnekte cursor'un (imlecin) nasıl tanımlandığını görmek için sadece kayıtları listeledik. Fakat çoğu zaman cursor'ları (imleçleri) sadece verileri listemek için kullanmak performansı olumsuz etkileyecektir. Cursor'ları (imleçleri) gerçekten ihtiyacımız olduğunda kullanmaya çalışmalıyız. Örneğimizde güncelle yapmak gerektiğinden, örnek ifademizi güncelleme yapmak üzere aşağıdaki gibi yenilememiz gerekecek.
DECLARE @fiyat MONEY
DECLARE @ cr_fiyatlar CURSOR
SET @ cr_fiyatlar = CURSOR FOR
SELECT price FROM titles
OPEN @ cr_fiyatlar FETCH NEXT FROM @ cr_fiyatlar INTO @fiyat
SELECT price FROM titles WHILE ( @@FETCH_STATUS = 0)
BEGIN
IF @fiyat < price =" (@fiyat">
WHERE CURRENT OF @ cr_fiyatlar ELSE
UPDATE titles SET price = (@fiyat + (@fiyat * .05))
WHERE CURRENT OF @ cr_fiyatlar FETCH NEXT FROM @ cr_fiyatlar INTO @fiyat
END
SELECT price FROM titles
CLOSE @ cr_fiyatlar DEALLOCATE @ cr_fiyatlar
Sekilde görüldüğü gibi yazdığımız T-SQL ifadesi sayesinde istediğimiz sonucu elde ettik. 20$ altındaki fiyatlar %10, 20$ ve üzerindeki fiyatlar %5 arttırılmış durumda.
Bu T-SQL ifadesinde kullandığımız SELECT ifadeleri ;

SELECT price FROM titles

sadece sonucu görmek içindi. Bu ifade olmasaydı güncelleme işlemi yine yapılacak fakat sonuçlar listelenmeyecekti.

Burada asıl dikkat etmemiz gereken WHERE CURRENT OF ifadesi. Bu ifade SQL Server'a o an cursor'un (imlecin) gösterdiği kayıt ile çalışmasını söyler.

Cursor'ların (imleçlerin) performans açısından çok tercih edilmediğini belirtmiştik. Bu yüzden gerekmedikçe cursor (imleç) kullanmamalıyız. Yukardaki örneğimiz için, T-SQL ifademizi biraz genişleterek (örneğin CASE yapısı ya da geçici tablolar kullanarak) cursor (imleç) kullanmadan aynı sonucu elde edebilirdik.

Cursor'lar (imleçler) satır satır hareket etmemize olanak sağlayarak kimi zaman işimizi çok kolaylaştırsalar da çoğu zaman performans kaybına sebep olurlar. Bu yüzden cursor (imleç) kullanmadan yapabileceğimiz işler için, gereksiz yere cursor (imleç) kullanmamaya çalışmalıyız.

0 Comments:

Yorum Gönder

<< Home