Excel VBA自动筛选除三个外的所有内容

3
在我进行数据分析的持续故事中(第一个问题),我想删除所有部门(字段7)不是101、102或103的行(名称已更改以保护无辜者)。数据中大约有一百个部门,因此使用Criteria1:=Array("104", "105", "106",等是不实际的。
我想做这样的事情:
myrange.AutoFilter Field:=7, Criteria1:="<>101", Operator:=xlOr, _
    Criteria2:="<>102", Operator:=xlOr, Criteria3:="<>103"

但是 Excel 不认识超过 2 个条件。我可以添加一个辅助列,并使宏运行每一行(如果为 101、102 或 103,则值=Yes),过滤出 Yes,然后删除所有剩余的内容,但我把这个方法留作最后的手段。
有没有一种方式可以将 Criteria1 自动筛选为不等于数组?类似于:
myrange.AutoFilter Field:=7, Criteria1:="<>" & Array("101", "102", "103")
4个回答

6

记住目标是删除不匹配的行;AutoFilter只是帮助实现这个目标的一个工具。如果AutoFilter不能满足您的需求,请选择另一种方法。可以考虑以下几个方面:

Sub AllBut()
    Dim rTable As Range, r As Range
    Dim rDelete As Range
    Set rTable = Selection
    Set rDelete = Nothing
    For Each r In rTable.Columns(7).Cells
        v = r.Value
        If v <> "101" And v <> "102" And v <> "103" Then
            If rDelete Is Nothing Then
                Set rDelete = r
            Else
                Set rDelete = Union(r, rDelete)
            End If
        End If
    Next

    If Not rDelete Is Nothing Then rDelete.EntireRow.Delete
End Sub

在这里,我们选择要处理的数据块(不包括标题行)。该宏扫描该块的第7列,并删除不符合条件的任何行。

剩下的只有101、102和103。


@garys-student 我很难理解这个。我猜第6行的意思是“对于我的数据中G列的每个单元格”,但我不确定它是如何实现的,因为r的范围从未设置。此外,我不熟悉Union函数。我是否正确地假设它将当前单元格添加到rDelete范围中? - Kes Perron
另外,v 不需要声明吗? - Kes Perron
1
@SMPerron: 你对自己的假设是正确的,在For循环中,每次通过循环时r都会被“设置”,不需要显式地“设置”。如果v没有进行Dim定义,则默认为Variant类型。打开一个全新的工作簿,在其中输入一些随意数据并尝试在那里运行宏。如果出现问题,您的真实数据将不会受到损坏.....祝你好运! - Gary's Student

4
由于这篇文章涉及到AutoFilter方法,我将提供一种使用Scripting.Dictionary对象来模拟在工作表上手动执行此过程的方法。
在工作表上,用户会应用一个自动筛选器,然后使用G列的下拉菜单“关闭”101、102和103值。剩下的内容将被删除。在VBA中,我们可以获取所有G列的值,并使用不是101、102或103的值填充字典对象,然后将其用作筛选操作的条件。
Sub filterNotThree()
    Dim d As Long, dDELs As Object, vVALs As Variant

    Set dDELs = CreateObject("Scripting.Dictionary")

    With Worksheets("Sheet6")
        If .AutoFilterMode Then .AutoFilterMode = False
        With .Cells(1, 1).CurrentRegion
            'grab all of column G (minus the header) into a variant array
            vVALs = .Resize(.Rows.Count - 1, 1).Offset(1, 6).Value2

            'populate the dictionary object with the values that are NOT 101, 102, or 103
            For d = LBound(vVALs, 1) To UBound(vVALs, 1)
                Select Case vVALs(d, 1)
                    Case 101, 102, 103
                        'do not add
                    Case Else
                        'not a match, add it to the delete list
                        'the AutoFilter criteria needs to be text
                        ' so we set the Keys as text and the Items as numbers
                        dDELs.Item(CStr(vVALs(d, 1))) = vVALs(d, 1)
                End Select
            Next d

            'check to make sure there is something to filter on
            If CBool(dDELs.Count) Then
                'filter on the dictionary keys
                .AutoFilter field:=7, Criteria1:=dDELs.keys, Operator:=xlFilterValues

                'delete the visible rows (there has to be some)
                .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0).EntireRow.Delete
            End If

        End With
        If .AutoFilterMode Then .AutoFilterMode = False
    End With

    dDELs.RemoveAll: Set dDELs = Nothing
End Sub

        filterNotThree_before
                经过 filterNotThree 子过程前的数据

        filterNotThree_after
                经过 filterNotThree 子过程后的数据


0

我之前也在做类似的事情,但是针对两个字段,这个语法对我有用:

myrange.AutoFilter Field:=7, Criteria1:="<>101", Operator:=xlAnd, Criteria2:="<>102", Operator:=xlAnd

希望能有所帮助。


-1

我知道现在有点晚了,但如果你需要超过2个条件,你必须使用数组。

myrange.AutoFilter Field:=7, Criteria1:=Array("<>101", "<>102", "<>103"), Operator:=xlFilterValues

这种方法不起作用,最多只能进行两个负面过滤。 - Cameron Critchlow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接