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?
İ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ış

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.

						
								i=1
								Do While i < 1000
								  If IsEmpty(Cells(i,1)) Then
									 Exit Do
								  End If
								  i = i + 1
								Loop

							
						
İçiçe Loop

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.
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ü

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.
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