Bármilyen apró VBA-kódunk megírása során kétfajta hibát követhetünk el, egyrészt véthetünk szintaktikai (alaki) hibát, amikor a program nem felel meg a VBA szabályainak, illetve véthetünk szemantikai (tartalmi) hibát, amikor a program lefut, de rossz eredménnyel, vagy futás közben le is áll. Ezeknek vannak könnyen és kevésbé könnyen felismerhető előfordulásai, a mai posztban megnézünk egy roppant egyszerű kis kódszeletet, az általa tartalmazott hibát és persze a megoldásról is ejtünk szót.
Adott a következő roppant egyszerű kis tábla (a példa egyszerűsége ne tévesszen meg minket, sokkal komolyabb tábláknál és programoknál is belefuthatunk ebbe a hibába):
Valamilyen komplexebb programunkba beépítve vagy akár önmagában is azt szeretnénk elérni, hogy ha a felhasználó megad egy cellaértéket és megnyom egy gombot, akkor a megadott cellaértéknek megfelelő sorok kerüljenek törlésre.
Erre elkészítjük a következő egyszerű kis kódot:
Sub sortorles()
Dim Tartomany As Range
Set Tartomany = ActiveSheet.Range("A1:A10")
For Each cell In Tartomany
If cell.Value = "Haza" Then
cell.EntireRow.Delete
End If
Next cell
End Sub
Boldogok is vagyunk, ott van szépen a For ciklusunk, ami a megadott tartomány összes celláján fog végigmenni és megnézi a feltétel teljesülését majd ennek megfelelően jár el, ha szükséges - az összes soron már nem megyek végig, az eddigi posztok alapján feltételezem, hogy ez már senkinek nem okoz komoly problémát. Futtassuk hát le! Előzetes becslésünk alapján a példánál azt várnánk, hogy maradjon két darab Otthon értékünk, semmi más, ehelyett a következőt kapjuk:
Vajon hol mehettünk félre? Hiszen szépen lefutott a program, nem is dobott hibát, mégsem az elvárt eredményt kaptuk. Azért a probléma önmagában egy tapasztalt VBA-felhasználónak nem okoz gondot, sőt valószínűleg elő sem idézi, de ettől függetlenül érdemes megvizsgálni ezt a kérdést.
A probléma a For ciklus "előrehaladásában" rejlik, ugyanis a ciklus mindig csak a következő sort vizsgálja meg a feltételnek megfelelően, tehát ha a kettes sort törölte, akkor újra már nem vizsgálja meg, miközben pedig a törlés miatt a hármas sorunk beugrott a kettes helyére és ez a sor vizsgálatlan maradt.
Jópár különféle megoldás van ennek a problémának a kiküszöbölésére, talán a legegyszerűbb, ha nem is megyünk bele ebbe a ciklusba, hanem egyszerűen tartományként meghatározzuk a törlendő cellákat és úgy hajtjuk végre azt a lépést, akár ki is színezhetjük a cellák hátterét, majd szín alapján törölhetünk, de akár csinálhatjuk azt is, hogy a For ciklust visszafelé futtatjuk (hiszen akkor nem lesz "előrehaladási" probléma), mondjuk így:
Sub sortorles()
Dim Tartomany As Range
Set Tartomany = ActiveSheet.Range("A1:A10")
For i = 10 To 1 Step -1
If ActiveSheet.Cells(i, 1) = "Haza" Then
ActiveSheet.Cells(i, 1).EntireRow.Delete
End If
Next i
End Sub
Ez sem túl bonyolult kód, ahogy látható, annyit változtattunk az előzőhöz képest, hogy az aktív sheetünk első oszlopában indulunk el a 10. cellától egyesével visszafelé az első celláig, és minden esetben megvizsgáljuk a ciklus éppen aktív cellájában a feltétel teljesülését majd ennek megfelelően törlünk.
Mondjuk ez 50 ezer sornál már nem lesz annyira szupergyors, úgyhogy inkább váltsunk ilyen esetekben egy másik megoldásra. Ötletek, javaslatok jöhetnek kommentben vagy akár Facebookon is.