Do ve While Döngüleri
For döngülerini incelerken gördük ki, bu döngüler genellikle çevrelenen kod parçasının kaç kez çalıştırılacağının bilindiği durumlarda kullanılmaktaydı.
Üst limitin bilinmediği diğer durumlarda ise çoğunlukla Do ve While döngüleri kullanıır. While ifadesi ile genelde "Do While" kalıbı içinde geçer ve bu aslında While döngüsü değil bir Do döngüsüdür. While Wend döngüsü artık çok kullanılan bir döngü olmayıp bu bölümdeki ve site genelindeki kodlarımızı Do döngüleriyle halletmeye çalışacağız. En son kısa bir While Wend döngü örneği de yapıp konuyu bitireceğiz.
Do döngüleri de For döngüleri gibi dizi ve dizimsilerde bol miktarda kullanılır, ayrınılı bilgi için For Döngüleri ve Diziler bölümlerine bakabilirsiniz.
Do döngülerinin 2 ana, 4 alt tipi vardır.
Do While
- Do While Şart şuysa.......Loop:Şart gerçekleşmezse çevrelenmiş kod hiç çalışmayabilir
- Do ....... Loop While Şart şuysa:Şart gerçekleşse de gerçekleşmese de en az 1 kez çalışır
Do Until
- Do Until Olay......Loop:Olay olana(şart gerçekleşene) kadar çalışır, döngüye girildiğinde olay zaten olmuşsa(şart gerçekleşmişse) çevrelenmiş kod hiç çalışmaz
- Do ....... Loop Until Olay:Olay olana(şart gerçekleşene) kadar çalışır; Çevrelenmiş kod en az 1 kez çalışır
Gördüğünüz üzere, şart eğer Do satırındaysa, kod hiç çalışmayabiliyor, ama Loop satırındaysa en az 1 kez çalışır.
Hemen bir örnek yapalım. Kullanıcıdan karesi alınacak bir sayı girmesini isteyelim ve eğer kullanıcı geçerli bir sayı yerine başka birşey mesela bir harf girerse başa dönmesini sağlayalım. Bunu bir If ve GoTo ile de yapabilirdik ama bu sefer Do ile yapacağız.
Sub dowhile1()
'bu en az 1 kere çalışır, ve sayı girene kadar bize aynı soruyu sorar
Do
sayı = InputBox("Karesi alınacak bir sayı girin")
Loop While Not IsNumeric(sayı)
MsgBox sayı & " sayısının karesi şudur:" & sayı * sayı
End Sub
Sub dowhile2()
'Bu ise soruyu hiç sormaz. Çünkü önce şart kontrolünü yapar,
'şart sağlanmadığı için döngüye girmeden çıkar
'Şart sağlanmaz çünkü say değişkeni varianttır ve
'Variantlara henüz değer atanmadıysa 0 değerini alır, yani IsNumeric sorugus True'dur
'başında da bir Not operatörü olduğu için şart sağlanmaz.
Do While Not IsNumeric(sayı)
sayı = InputBox("Karesi alınacak bir sayı girin")
Loop
MsgBox sayı & " sayısının karesi şudur:" & sayı * sayı
End Sub
Aşağıda ise Do Until yapısına ait 2 örnek bulunuyor.
Sub dountil1()
'sayfa sayısı 5 olana kadar işlem yapar. 5ten çoksa siler azsa ekler.
Application.DisplayAlerts = False
If Sheets.Count < 5 Then
Do Until Sheets.Count = 5
Sheets.Add After:=Sheets(Sheets.Count)
Loop
ElseIf Sheets.Count > 5 Then
Do Until Sheets.Count = 5
Sheets(Sheets.Count).Delete
Loop
End If
End Sub
Sub dountil2()
'en az bir kere çalışır, taki sayfa sayısı 1 olana kadar
Do
Sheets(2).Delete 'Her defasında hep 2.sayfa silinir, ta ki tek sayafana kalana kadar
Loop Until Sheets.Count = 1
End Sub
While mı Until mi?
Hangi durumda hangisini kullanmalıyız?
For döngülerinde olduğu gibi Do Looplarından çıkış için de Exit ifadesini kullanırız. Mesela aşağıdaki döngüde, boş bir hücreye rastlanıldığında döngüden çıkılır.
Diyelim ki bir bölgenin şubelerini hacimlerine göre boy sırasına dizdiniz, buna göre her bölgenin en yüksek hacimli rakamını yazdırmak istiyorsunuz, yani bir nevi Excelde varolmayan(2016da MAXIFS geldi) bir MAXIF fonksiyonunu Sub prosedür olarak ele alacağız ve bunun tersi olan MINIF'i.
Başta da söylediğimiz gibi bu döngü tipi artık pek kullanılmıyor, sadece eski yazılmış bir kod karşımıza geldiğinde bilelim diye hala var. Ama MSDN'nin bize söylediği gibi, Do Döngüsü daha fonksiyonel ve esnektir ve yeni kodlarda bu kullanılmaldır.
İkisini de her durumda kullanabilirsiniz. Tek farkı, birini diğerinin tersi mantıkla yazmak. Geliştiriciler neden böyle bir ayrıma girmişler emin değilim ama sanırım konuşma dilindeki kullanım terchilerimizi gözönüde bulundurmuş olabilirler. Mesela çocuğumuza "yemeğin bitene kadar masadan kalkmak yok" da diyebilriz, "yemeğin bitmediği sürece masadan ayrılmak yok" da, ikisi de aynı kapıya çıkar. VBA'de de durum pek farklı değil: En alt satıra inene kadar çalış da diyebiliriz, "aktif satır no
Döngüden Çıkış
i=1
Do While i < 1000
If IsEmpty(Cells(i,1)) Then
Exit Do
End If
i = i + 1
Loop
İçiçe Loop
Tabiki bunları bir UDF ile yapmak daha şık olackatır ancak içiçe Loop örneği görmek adına bu örnek faydalı olacaktır.
Sub maxif()
'maxı yazacağın yere gel, ordayken çalıştır ve liste sıralı olsun
Set kriter = Application.InputBox("ana değişken kriterinin olduğu sütundan bir hücre seç", Type:=8)
Set rakam = Application.InputBox("maksimumun arandığı sütunu seç", Type:=8)
ks = ActiveCell.Column - kriter.Column
rs = ActiveCell.Column - rakam.Column
Do
Maks = ActiveCell.Offset(0, -rs).Value
Set ilkyer = ActiveCell
Do While ActiveCell.Offset(0, -ks).Value = ActiveCell.Offset(1, -ks).Value
If ActiveCell.Offset(1, -rs).Value > Maks Then Maks = ActiveCell.Offset(1, -rs)
ActiveCell.Offset(1, 0).Select
Loop
Set sonyer = ActiveCell
Range(ilkyer, sonyer).Value = Maks
ActiveCell.Offset(1, 0).Select
Loop Until ActiveCell.Offset(0, -1).Value = ""
End Sub
Sub minif()
'mini yazacağın yere gel, ordayken çalışıtır ve liste sıralı olsun
Set kriter = Application.InputBox("ana değişken kriterinin olduğu sütundan bir hücre seç", Type:=8)
Set rakam = Application.InputBox("minimumun arandığı sütunu seç", Type:=8)
ks = ActiveCell.Column - kriter.Column
rs = ActiveCell.Column - rakam.Column
Do
Mini = ActiveCell.Offset(0, -rs).Value
Set ilkyer = ActiveCell
Do While ActiveCell.Offset(0, -ks).Value = ActiveCell.Offset(1, -ks).Value
If ActiveCell.Offset(1, -rs).Value <= Mini Then Mini = ActiveCell.Offset(1, -rs)
ActiveCell.Offset(1, 0).Select
Loop
Set sonyer = ActiveCell
Range(ilkyer, sonyer).Value = Mini
ActiveCell.Offset(1, 0).Select
Loop Until ActiveCell.Offset(0, -1).Value = ""
End Sub
While Wend döngüsü
While döngülerinde sadece başta şart kontrolü yapılır, yani en az 1 kere çalışma olayı bunda seçime bağlı değildir. Bu da demektir ki döngü içindeki kodumuzun hiç çalışmaması mümküdür. Ayrıca Do ve For dönülerindeki gibi döngüden çıkış ifadesi(Exit) de yoktur.
Aşağıdaki örnekte 1'den 10 kadar olan sayıların toplamını alıyoruz.
Sub topla()
While sayı <= 10
toplam = toplam + sayı
sayı = sayı + 1
Wend
MsgBox toplam
End Sub)
Bir hücre grubuna harfleri yazdırma
Sub harfyaz()
Dim i As Integer
i = 1
Do While i < 27
Cells(i, 1) = Chr(i + 64) 'A harfinin Ascii kodu 65tir
i = i + 1
Loop
End Sub
İlk sayfa hariç tüm sayfaları silme
Do
Sheets(2).Delete 'Her defasında hep 2.sayfa silinir, ta ki tek sayafana kalana kadar
Loop Until Sheets.Count = 1
Database'den tek tek tarihler için data çekip başka sayfada altalta getirme
Diyelim ki, bir nedenle tarihsel datasını tek tek çekmeniz gereken bir sorgu var. Ör:1 Ocak için ayrı, 2 Ocak için ayrı,.... v.s Bunu bir SQL ortamında yapmanız ağır bir iş gelebilir. Neyse ki VBA ve döngüler sayesinde bu ağır iş bile kolaylaşabilir.
Sub dowhileornek()
Dim t As Date
t = "01.01.2016"
Do
'SQL stringini oluşturuyorum
s1 = "Select * from PARG.ARG_TNETICE_MUSTERI_GER" & Chr(13)
s2 = "where BAGLI_URUN_ID in (165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184)"
s3 = "and TARIH=" & t & " and KPI_ID=1001 and RAPOR_TURU=2"
s4 = "and musteri_id in (Select ESLESEN_TARAF_ID from PDWH.DWH_TSAKLAMA where YONLENDIREN_SUBE <> 1234 and TARIH=t)" & Chr(13)
With ActiveWorkbook.Connections("DWH").ODBCConnection
.BackgroundQuery = True
.CommandText = Join$(Array(s1 & s2 & s3 & s4))
'Diğer kodlar
End With
ActiveWorkbook.Connections("Query from PDWH_USR").Refresh
t = t + 1 'Tarihi 1 artırıyorum
ActiveCell.CurrentRegion.Select
Selection.Copy
Sheets(2).Select
ActiveCell.Offset(1, 0).Select
ActiveSheet.Paste 'ilk çalışan sorgu sonucunu 2.sayfaya ekleyip bir alt satıra iniyorum
Loop Until t = "15.02.2016" '15 şubata kadar yani 45 kez sorgu çalışacak
'SQL ortamınıda bunu yapmak çok yorucu olabilirdi
End Sub
Belirli adette sayfası olan dosya yaratma
Diyelim ki, kodumuzun bir yerinde 5 sayfalı bir workbook yaratmamız gerekiyor. Normalde Excelin default ayarı yeni workbook açılıdığında 3 adet safyası olması yönündedir ama biz bu default ayarı değiştirmiş olabiliriz, mesela 1 veya 7 yapmış olabiliriz. O yüzden ilk olarak bir If bloğu ile kontrol ederiz ve eğer 5 ten büyükse fazlalıkları sildirip, küçükse 5e tamamlayan bir kod yazarız. Sayfa sayımız zaten 5se kod hiçbirşey yapmaz.
Sub sayfaekleveyasil()
Application.DisplayAlerts = False 'sayfa silerken uyarmasın
If Sheets.Count < 5 Then
Do Until Sheets.Count = 5
Sheets.Add After:=Sheets(Sheets.Count)
Loop
ElseIf Sheets.Count > 5 Then
Do Until Sheets.Count = 5
Sheets(Sheets.Count).Delete
Loop
End If
End Sub