【问题标题】:Excel VBA deleting rows in a for loop misses rowsExcel VBA在for循环中删除行会丢失行
【发布时间】:2017-09-13 05:28:37
【问题描述】:

我有一个子例程可以删除包含大约 1000 行的范围内的行。 在标准上删除行。 下面的代码有效。

但是,当我运行宏时,我通常必须运行 4 次才能删除包含删除条件的所有行。

我猜这是因为删除一行时,当一行突然消失时,for循环错过了它的索引。

我的第一个代码如下所示。

Set StatusRange = Range("B2", Range("B2").End(xlDown))

For Each StatusCell In StatusRange
    If StatusCell = "FG" Then
        StatusCell.EntireRow.Delete
    ElseIf StatusCell = "QC" Then
        StatusCell.EntireRow.Delete
    ElseIf StatusCell = "CS" Then
        StatusCell.EntireRow.Delete
    Else
    End If
Next StatusCell

当我尝试更新每个循环的范围时,它仍然不起作用。

Set StatusRange = Range("B2", Range("B2").End(xlDown))

For Each StatusCell In StatusRange
    If StatusCell = "FG" Then
        StatusCell.EntireRow.Delete
    ElseIf StatusCell = "QC" Then
        StatusCell.EntireRow.Delete
    ElseIf StatusCell = "CS" Then
        StatusCell.EntireRow.Delete
    Else
    End If
                
    Set StatusRange = Range("B2", Range("B2").End(xlDown))
Next StatusCell
        

有没有人知道这个问题?

【问题讨论】:

  • 自下而上工作。如果您删除一行,所有内容都会向上移动,并且您会在下一次迭代中跳过该行。
  • 这几乎可以肯定是一个重复的问题,当我找到合适的重复时我会这样标记它。每当您从集合中删除项目时,您必须Rows.Count to 1 Step -1 中删除,否则您将跳过行。
  • 继续欺骗@DavidZemens - 我通过显示多重比较的 Case 语句增加了一些价值,但这仍然是一个欺骗。
  • 这里有一个很好的解释:stackoverflow.com/questions/23689196/…
  • 另一个有一个公认的答案,实际上似乎是 VB.NET 代码,但原理是一样的:stackoverflow.com/questions/10315120/…

标签: vba excel


【解决方案1】:

自下而上工作。如果您删除一行,所有内容都会向上移动,并且您会在下一次迭代中跳过该行。

这是从底部开始工作的代码的“胆量”。

With Worksheets("Sheet1")
    For rw = .Cells(.Rows.Count, "B").End(xlUp).Row To 2 Step -1
        Select Case UCase(.Cells(rw, "B").Value2)
            Case "FG", "QC", "CS"
                .Rows(rw).EntireRow.Delete
        End Select
    Next rw
End With

【讨论】:

  • 我写的是同样的答案(完整的Case声明)哈哈:D
  • 该死,我刚刚输入并发布了几乎完全相同的代码;)
【解决方案2】:

由于For Each 没有反向循环,您需要使用稍微不同的方法。

另外,您的代码包含多个Ifs 和OR 是“尖叫​​着使用Select Case

Dim StatusRange As Range
Dim i As Long

Set StatusRange = Range("B2", Range("B2").End(xlDown))

' loop backward when deleting Ranges, Rows, Cells
For i = StatusRange.Rows.Count To 1 Step -1
    Select Case StatusRange(i, 1).Value
        Case "FG", "QC", "CS"
            StatusRange(i, 1).EntireRow.Delete
        Case Else ' for the future if you need it

    End Select
Next i

【讨论】:

    【解决方案3】:

    等到For Each 循环结束后再删除行:

    Option Explicit
    
    Sub mySub()
    
        Dim myRange As Range
        Set myRange = ActiveSheet.UsedRange
    
        Dim myCell As Range
        Dim myTrash As Range
    
        For Each myCell In myRange
            Select Case myCell.Value
                Case "my value"
                    If myTrash Is Nothing _
                        Then
                            Set myTrash = myCell.EntireRow
                        Else
                            Set myTrash = Union(myTrash, myCell.EntireRow)
                    End If
            End Select
        Next
    
        If Not myTrash Is Nothing Then myTrash.Delete
    
    End Sub
    

    【讨论】:

    • 对我来说这实际上是最好的解决方案。我只是在 Union() 之前添加了If rngToBeDeleted Is Nothing Then Set rngToBeDeleted = xlRow.EntireRow 以避免最初未设置范围时出错。
    【解决方案4】:
    start_over: s = 0  
        for each cell  
            if cell = "FG" then   
               s = 1            'Marked to start over if ifstmt was true
               [other code]
            end if  
        next cell  
       If s = 1 Then GoTo start_over  
    

    '你的代码:

    Set StatusRange = Range("B2", Range("B2").End(xlDown))  
        start_over: s = 0  
        For Each StatusCell In StatusRange  
            If StatusCell = "FG" or StatusCell = "QC" or StatusCell = "CS" Then StatusCell.EntireRow.Delete: s=1  
        Next StatusCell  
       If s = 1 Then GoTo start_over
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多