Cursor vs While
İnsan Kaynakları Müdürü olduğumuzu düşünelim. Kariyer planı ile ilgili olarak firma da çalışan mühendislerin dosyalarını inceleyip önceki yıllardakı başarı/başarısızlık ve performans değerlendirme sonuçlarına göre puanlama yapacağız. Elimizin altında da bir yardımcımız vardır.
Bu durumda ne yapardık.
a) Yardımcımızdan firmadaki bütün mühendislerin dosyalarından istediğimiz bilgileri toplayıp bir kutuya doldurmasını ve masamızın üstüne koymasını isteyebiliriz.
b) Yardımcımızdan isim veya personel numarası vererek her seferinde bir mühendisin dosyasını inceleyip puan verebiliriz. Sonra yine yeni bir numara vererek o numaradaki mühendisin dosyasıını isteyebiliriz.
Hikaye bundan ibaret. Şimdi gelelim bu örneği Cursor ve While ile yorumlamaya.
1 nci metodla çalışırsanız; (CURSOR)
1- Bir personel listesine ihtiyacımız olmaz.
2- Bir daha yardımcıya ihtiyacımız olmaz
3- Bütün dosyalar elimizin altındadır
4- İşlediğimiz dosyayı kenara koyup, masanızdan yeni bir tane alabiliriz. Aldığımız dosyanın bir mühendise ait olmaması gibi bir durum söz konusu değildir. Bu kontrolu yapma ihtiyacı duymayız
2 nci metodla çalışırsanız; (WHILE)
1- Ne kadar işimiz kalmış bilebiliriz
2- Masamız tertemiz,
3- Yardımcımızın bütün dosyaları yığıp getirmesi uzun sürer halbuki biz bana şu nuramalı personeli ver dediğinizde onun yeri ve sırası bellidir.
4-Performansımız daha fazladır.
Şimdi bu yapıyı kurgulayıp örnekleyelim.
Create TABLE Person (Id INT, Name VARCHAR(20), Department VARCHAR(100), P1 INT,P2 INT, P3 INT, IsEngineer BIT )
INSERT INTO Person (Id, Name, Department,P1,P2,P3, IsEngineer) VALUES ( 1,'Ali','BT',10,20,25,1),(2, 'Ahmet','IK',50,40,10,0),(3, 'Osman','IK',60,70,80,1),( 4, 'Hasan','BT',60,40,70,1),(5, 'Memet','BT',10,20,30,0)
sonunda elimizde aşağıdaki gibir tablo bulunmaktadır
Cursor ile çözüm
Cursor de işler neler yapılıyor.
1- Önce bir kutu tanımlayıp bütün mühendislerin Name, Department,P1,P2,P3 bilgilerini bu kutuya dolduracağız
2- Sonra Bu kutuyu açacağız
3- Her defasında bir mühendis için Name, Department,P1,P2,P3 bilgilerini alıp not defterimize işleceğiz.
4- Bu işi kutuda belge kaldığı sürece yapacağız.
5-Okuduğumuz her mühendis bilgisini işleyeceğiz- performans değerlendirmesi yapacağız.
6-Kutuyu kapatacağız.
7-Kutuyu geri gönderip işlemi bitireceğiz.
SQL :
-- bu değişkenler okuduğumuz her personel için -- her satırda yeniden dolacak. Yani biz bir sonrakini -- ver dediğimizde sıradaki personel kimse onun bilgileri dolacak declare @Id int declare @Name varchar (20) declare @Department varchar (100) declare @P1 int declare @P2 int declare @P3 int -- 1 : Bir kutu tanımladım (_personCursor). O kutuya personellerin Name, Department,P1,P2,P3 -- bilgilerini ekledik DECLARE _personCursor CURSOR FOR SELECT Id, Name, Department,P1,P2,P3 FROM Person WHERE IsEngineer=1 -- Adım 2: Kutuyu açtık artık okumaya hazırız OPEN _personCursor -- 3- Her defasında bir mühendis için Name, Department,P1,P2,P3 bilgilerini alıp not defterimize işleceğiz. -- NOT buradaki parametlerin sırası yukardaki select te yazılan sıra ile aynı olmalıdır. yani @P2 ile @P3 ün yeri değiştiğinde -- değerleri de değişektir. */ FETCH NEXT FROM _personCursor INTO @Id,@Name,@Department,@P1,@P2,@P3 -- 4- Bu işi kutuda belge kaldığı sürece yapacağız. WHILE @@FETCH_STATUS = 0 BEGIN -- burada satır satır aldığımız kayıtlarla istediğimiz işlemi yapabiliriz. Örn: -- işlemler { -- 5-Okuduğumuz her mühendis bilgisini işleyeceğiz- performans değerlendirmesi yapacağız. --} --4 İşini bitirdiğin kaydı kenra koy bir sonrakini oku FETCH NEXT FROM _personCursor INTO @ID END -- 6-Kutuyu kapatacağız. CLOSE _personCursor -- 7-Kutuyu geri gönderip işlemi bitireceğiz. DEALLOCATE _personCursor
Not: Cursor ile ilgili sadece FETCH NEXT değil daha başka değişkenler (FAST_FORWARD,OPTIMISTIC vs) parametrelerde kullanabilirsiniz. Yapmak istediğiniz iş için hangi parametre kullanacağınız size kalmış. Bütün paremetrelerin açıklamalarını tek tek verip makaleyi şişirmek istemiyorum. Msdn yada bu linkten açıklamalara ulaşabilirsiniz.
While ile çözüm
While ile bu işi yapmanın bir kaç yolu vardır.
Birincisi.
declare @Name varchar (20) declare @Department varchar (100) declare @P1 int declare @P2 int declare @P3 int -- @Rows tanılandığında 1 değerini almıştır dolayısı ile -- aşağıdaki döngüye girecektir. -- @Rows > 0 olduğu sürece aşağıdaki döngü devam edecektir WHILE @Rows>0 BEGIN -- @Id bu sorgu neticesinde dönen kayıtların ilkinin (en küçük) Id sini alıyor Select Top 1 @Name=Name,@Department = Department,@P1=P1,@P2=P2,@P3=P3, @Id=Id from Person where IsEngineer=1 and Id>@Id --@Id herzaman bir öncekinden büyük bir değer alacağı için küçükten -- büyüğe doğru bir iterasyon olacaktır -- @Rows sorgudan dönen, kritere uyan kayıt varsa işlem -- If blogü içinde yapacak değilse döngüden çıkacaktır set @Rows =@@RowCount if @Rows>0 begin -- işlemler{ -- Performans değerlendirme işlemler yapılıyor --} end END
İkincisi ve tahmin ediyorum daha çok kullanılanı; işlenecek olan kayıtların Id lerinin geçici bir tabloya atılarak dönügünün onun üzerinden çalıştırmaktır.
-- while için kullanılıacak değişkenler declare @Count int = 0 declare @Id int = 1 declare @PersonId int declare @Name varchar (20) declare @Department varchar (100) declare @P1 int declare @P2 int declare @P3 int -- 1 den başlayıp sorgudan dönen kayıt sayısı kadar artan bir unique id ile -- döngü yapılacak olan kayıtlar bir temp tabloya atılyor select ROW_NUMBER() OVER (ORDER BY Id) as Id, Id as PersonId, Name, Department,P1,P2,P3 into #dt from Person where IsEngineer=1 -- temp tabloda kayıt sayısı alınıyır select @Count= count(*) from #dt -- while koşulu oluşturuluyır @Id =1 olduğu için -- ve her satırda 1 artacağı için sonunda @Count a eşit olduğunda -- artık döngü tamamlanmış olacaktır WHILE @Id<=@Count BEGIN -- @Id ile temp tabledeki unique Id eşleşiyor. PersonId değeri ve diğer -- değişkenler değerleri alıyor Select Top 1 @Name=Name,@Department = Department,@P1=P1,@P2=P2,@P3=P3, @PersonId=PersonId from #dt where Id=@Id select @P1 -- işlemler{ -- Performans değerlendirme işlemler yapılıyor --} -- iterasyon için @Id arttırılıyor set @Id=@Id+1 END
Sonuç: ben duruma göre kullanıyorum. - Eğer kırkyılın başında kullanacaksam ve içinde epeyce mantıksal işlem yapacaksam ve persormans sorunum yoksa Cursor kullanmayı tercih ediyorum. - yapmak istediğim şey basit bir işlem ise while kullanıyorum onda da ilk gösterdiğim @Rows ile yapıyorum.
2015 : memet tayanç