Excel VBA autofilter all but three
Asked Answered
K

4

3

In the continuing saga of my data analysis (First Question), I want to delete all the rows whose departments (Field 7) are not 101, 102 or 103 (the names have been changed to protect the innocent). There are about a hundred departments in the data, so using Criteria1:=Array("104", "105", "106", etc is impractical.

I would like to do something like this:

myrange.AutoFilter Field:=7, Criteria1:="<>101", Operator:=xlOr, _
    Criteria2:="<>102", Operator:=xlOr, Criteria3:="<>103"

but Excel doesn't recognize more than 2 Criteria. I could add a helper column, and have the macro run through each line (if 101, 102, or 103, then value=Yes), filter out the yeses, and delete all that remain, but I'm saving that as a last resort.

Is there a way to Autofilter Criteria1 to be Not Equal To an array? Something like:

myrange.AutoFilter Field:=7, Criteria1:="<>" & Array("101", "102", "103")
Kush answered 21/10, 2013 at 14:46 Comment(0)
R
6

Remember the goal is to delete the non-matching rows; AutoFilter is only one tool to help achieve the goal. If AutoFilter does not meet your needs, pick another method. Consider:

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

Here we select the block of data to be processed (not including the header row). The macro sweeps down column #7 of that block and deletes any row that does not match the criteria.

All that will remain are the 101's, the 102's, and the 103's.

Ryon answered 21/10, 2013 at 15:19 Comment(3)
@garys-student I'm having a hard time following this. I assume that line 6 means "For each cell in column G of my data" but I'm not sure how that is since the range for r is never set. Also, I'm not familiar with the Union function. Am I correct in assuming that it adds the current cell to the range rDelete?Kush
Also, doesn't v need to be declared?Kush
@SMPerron : You are correct on your assumptions, in a For loop, r is "set" each time thru the loop and does not need to be "set" explicitly. If v is not Dim'ed it is assumed to be Variant. Open a fresh, new workbook, put some scratch data in it and try the macro out there. If things go wrong, your real data will not get corrupted.....Good Luck!Vitellus
F
4

Since this was about the AutoFilter method, I'll offer up this method involving using a Scripting.Dictionary object to mimic the procedure that would be used if this was manually performed on the worksheet.

On the worksheet, the user would apply an AutoFilter then use column G's drop down to 'turn off' the 101, 102 and 103 values. What remained would be be deleted. In VBA, we can grab all of column G and populate a dictionary object with the values that are not 101, 102 or 103 and use that as the criteria for the filter operation.

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
                Data before filterNotThree sub procedure

        filterNotThree_after
                Data after filterNotThree sub procedure

Flavin answered 31/1, 2016 at 21:58 Comment(0)
U
-1

I was doing something similar but for two fields and this syntax worked for me:

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

Hope it helps.

Unsphere answered 3/2, 2016 at 14:39 Comment(0)
S
-1

I know this is late but if you need more than 2 criteria, you have to use an array.

myrange.AutoFilter Field:=7, Criteria1:=Array("<>101", "<>102", "<>103"), Operator:=xlFilterValues
Septuple answered 7/4, 2021 at 18:8 Comment(1)
This method does not work, the most you can negatively filter are two.Hundred

© 2022 - 2024 — McMap. All rights reserved.