Image
Eylül 13 2015 02:28

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 

sql

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ç