【问题标题】:Delete rows (dynamic amount) based on cell's content根据单元格内容删除行(动态数量)
【发布时间】:2013-12-19 23:47:35
【问题描述】:

对不起,如果这很简单,这是我第一次尝试 VBA。

所以我希望这个宏删除我不需要的行,并且对于每个实体,它都有一个总字段(大约每 20 条记录左右),我制作了这个脚本:

Dim i As Integer
Dim LastRow As Integer
LastRow = Range("A65536").End(xlUp).Row

For i = 3 To LastRow
    If Range("C" & i) = "Result" Then
        Rows(i & ":" & i).Select
        Selection.Delete Shift:=x1Up
    End If
Next

而且效果很好!然后我尝试了类似的事情。我尝试遍历数据集中的每一行(记录),然后如果某个字段不包含字符串“INVOICE”,那么我不需要该行,我可以删除它.所以我只是添加到我当前的循环中(为什么循环两次?)所以现在看起来像这样:

Dim i As Integer
Dim LastRow As Integer
LastRow = Range("A65536").End(xlUp).Row

For i = 3 To LastRow
    If Range("C" & i) = "Result" Then
        Rows(i & ":" & i).Select
        Selection.Delete Shift:=x1Up
    End If
    If Not InStr(1, Range("Q" & i), "INVOICE") Then
        Rows(i & ":" & i).Select
        Selection.Delete Shift:=x1Up
    End If
Next

据我所知,第二位只是随机开始删除行,没有押韵或理由。 Q 字段不包含发票的行有时会保留有时会消失,如果包含发票则相同。知道我做错了什么吗?

【问题讨论】:

  • 不要循环播放。使用自动过滤器 :) 见THIS
  • ...或者如果您要循环,则从最后一行开始并继续工作 (For i = LastRow to 3 Step -1),这样您在删除一行时就不会踩到循环索引 (因此向上移动下面的行...)

标签: vba loops excel range


【解决方案1】:

您应该将OR 您的条件放在一起,以便如果存在任何一个原因,则删除该行。否则,由于您要删除预设范围内的行,因此您最终会跳过比当前更多的行。目前看起来你每次删除一行时都会跳过一行,所以你错过了任何连续的案例。 Tim 建议从最后一排开始工作。

For i = LastRow to 3 Step -1
  If Range("C" & i) = "Result" OR Not InStr(1, Range("Q" & i), "INVOICE") Then
    Rows(i & ":" i).Delete Shift:=x1Up
  End If
Next i

【讨论】:

  • 有道理,感谢您的帮助!我想我会切换到自动筛选选项,因为它更快而且我的数据集非常庞大。
【解决方案2】:

确实有两种方法:AutoFilterFor Loop。在这两者中,AutoFilter 速度要快得多,尤其是在处理大型数据集时,但它通常需要非常好的设置。 For Loop 很简单,但它有边际回报,尤其是当您的数据开始达到 10 万行或更多时。

另外,Not InStr(1, Range("Q" & i), "INVOICE") 似乎是最好的方法,但恕我直言,事实并非如此。 InStr 返回一个数字,所以最好像Not InStr(1, Range("Q" & i), "INVOICE") > 0 那样做进一步的比较,或者只是简单的InStr(1, Range("Q" & i), "INVOICE") = 0。无论如何,我在下面的第二个代码中使用了前者。

以下是两种方法。他们在简单的数据上进行测试。代码可能看起来有点笨重,但逻辑是合理的。其他内容也请参阅 cmets。

自动过滤方法:

Sub RemoveViaFilter()

    Dim WS As Worksheet: Set WS = ThisWorkbook.Sheets("ModifyMe")
    Dim LastRow As Long

    Application.ScreenUpdating = False
    With WS
        '--For condition "Result"
        .AutoFilterMode = False
        LastRow = .Cells(Rows.Count, 1).End(xlUp).row '--Compatible if there are more rows.
        With Range("A2:Q" & LastRow) '--Assuming your header is in Row 2 and records start at Row 3.
            .AutoFilter Field:=3, Criteria1:="Result" '--Field:=3 is Column C if data starts at A
            .Cells.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete '--Delete the visible ones.
        End With
        '--For condition "<>*INVOICE*"
        .AutoFilterMode = False
        LastRow = .Cells(Rows.Count, 1).End(xlUp).row
        With Range("A2:Q" & LastRow)
            .AutoFilter Field:=17, Criteria1:="<>*INVOICE*" '--Field:=17 is Column Q if data starts at A
            .Cells.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
        End With
        .AutoFilterMode = False
    End With
    Application.ScreenUpdating = True

End Sub

For循环方法:

Sub RemoveViaLoop()

    Dim WS As Worksheet: Set WS = ThisWorkbook.Sheets("Sheet6")
    Dim LastRow As Long: LastRow = WS.Cells(Rows.Count, 1).End(xlUp).row
    Dim Iter As Long

    Application.ScreenUpdating = False
    With WS
        For Iter = LastRow To 3 Step -1 '--Move through the rows from bottom to up by 1 step (row) at a time.
            If .Range("C" & Iter) = "Result" Or Not InStr(1, .Range("Q" & Iter).Value, "Invoice") > 0 Then
                .Rows(Iter).EntireRow.Delete
            End If
        Next Iter
    End With
    Application.ScreenUpdating = True

End Sub

如果这有帮助,请告诉我们。

【讨论】:

  • 谢谢,我今天将使用自动过滤器尝试一下,因为我的数据集可能会变得庞大,而且它正在运行我不想陷入困境的后台机器。
猜你喜欢
  • 2014-06-07
  • 1970-01-01
  • 2013-08-10
  • 2013-10-14
  • 2017-03-07
  • 2018-11-11
  • 1970-01-01
  • 2018-02-13
  • 1970-01-01
相关资源
最近更新 更多