VBA 循环与判断:For、For Each、Do While、Select Case

适用场景

逐行检查数据、遍历所有工作表、批量删除空白行、按条件跳过某些记录。VBA 的循环语法不复杂,但“边循环边删除行”和“修改集合的同时遍历”很容易漏数据。

For 循环

Dim i As Long
For i = 1 To 10
    Debug.Print i
Next i

For i = 10 To 1 Step -1
    Debug.Print i
Next i

For i = 1 To 10 Step 2
    Debug.Print i
Next i

遍历单元格

Sub CheckRows()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long

    Set ws = ThisWorkbook.Worksheets("数据")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    For i = 2 To lastRow
        If ws.Cells(i, "C").Value < 0 Then
            ws.Cells(i, "D").Value = "异常"
        Else
            ws.Cells(i, "D").Value = "正常"
        End If
    Next i
End Sub

数据量大时不要逐格读写,先读入数组、循环数组、再写回,见 vba-range-cells。

For Each

Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
    Debug.Print ws.Name
Next ws

Dim cell As Range
For Each cell In ws.Range("A2:A" & lastRow)
    If cell.Value = "" Then cell.Interior.Color = RGB(255, 235, 156)
Next cell

For Each 适合遍历集合,但不要在遍历集合的同时删除元素:删除一个工作表后,集合索引会变化,后面的元素可能被跳过。要删除时用倒序的 For i = ... To ... Step -1。

Do While / Do Until

Dim i As Long
i = 1
Do While i <= 10
    Debug.Print i
    i = i + 1
Loop

i = 1
Do Until i > 10
    Debug.Print i
    i = i + 1
Loop

还有“先执行一次再判断”的写法:

Do
    Debug.Print i
    i = i + 1
Loop While i <= 10

Exit Do 可以提前跳出。写 Do While 时确认循环体里一定会修改条件变量,否则会死循环;调试时按 Ctrl+Break 中断。

If / ElseIf / Select Case

If score >= 90 Then
    grade = "优秀"
ElseIf score >= 80 Then
    grade = "良好"
ElseIf score >= 60 Then
    grade = "及格"
Else
    grade = "不及格"
End If
Select Case grade
    Case "A"
        bonus = 1000
    Case "B"
        bonus = 500
    Case Else
        bonus = 0
End Select

Select Case 适合等值分支,范围判断用 Case Is >= 90:

Select Case score
    Case Is >= 90
        grade = "优秀"
    Case Is >= 60
        grade = "及格"
    Case Else
        grade = "不及格"
End Select

倒序删除行

正序删除会跳过下一行:

Sub DeleteBlankRows()
    Dim ws As Worksheet
    Dim i As Long

    Set ws = ThisWorkbook.Worksheets("数据")
    Application.ScreenUpdating = False

    For i = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row To 2 Step -1
        If Trim(ws.Cells(i, "A").Value & "") = "" Then
            ws.Rows(i).Delete
        End If
    Next i

    Application.ScreenUpdating = True
End Sub

从最后一行往前删,当前行删除后不会影响尚未处理的行。也可以用 AutoFilter 筛出空白行后一次删除可见行,速度更快。

易错点

相关条目

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. 为什么删除行要从最后一行往前循环?
  2. For Each 遍历工作表时为什么不能直接 Delete?
  3. VBA 的 And/Or 有短路求值吗?
答案
  1. 正序删除后下一行会上移,循环变量继续加一会跳过它;倒序删除不影响未处理行。
  2. 删除元素会改变集合索引,后面的元素可能被跳过;应改用倒序索引。
  3. 没有,两边都会计算;需要短路时用嵌套 If。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令