I want to create an autofilter macro for an excel sheet, that will filter out any rows that do not contain "ballroom*" in Column E, but will also leave any rows where Column E is empty
Have basic programming knowledge, have taught myself what I know thus far in VBA
This is what I have currently
Sub row_deleter()
Dim ws As Worksheet
Dim rng As Range
Dim lastrow As Long
''setting varibles
Set ws = ActiveSheet
lastrow = ws.Range("E" & ws.Rows.count).End(xlUp).Row
Set rng = ws.Range("E1:E" & lastrow)
''actual filter function
With rng
.AutoFilter field:=5, Criteria1:=IsEmpty(rng), Operator:=xlAnd, Criteria2:="=*ballroom*"
.SpecialCells(xlCellTypeVisible).EntireRow.delete
End With
''turn off filters
ws.AutoFilterMode = False
End Sub
When I try to run this code it gives me a 1004 error saying `AutoFilter` method of range class failed, and the debug points to the `AutoFilter` line. Have tried a few things thus far with syntax etc and nothing seems to be working.
First, let's make sure that your table has an AutoFilter. Additionally, your criteria shouldn't be relevant to any range, just what's being filtered. Also, I believe your criteria should be xlOr - a cell can't be blank AND have ballroom in it. Try this:
Sub row_deleter()
Dim ws As Worksheet
Dim rng As Range
Dim lastrow As Long
''setting varibles
Set ws = ActiveSheet
lastrow = ws.Range("E" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("E1:E" & lastrow)
''turn on autofilter if it's off
If ws.AutoFilterMode = False Then
ws.UsedRange.AutoFilter
End If
''actual filter function
With rng
.AutoFilter Field:=1, Criteria1:="=", Operator:=xlOr, Criteria2:="=*ballroom*"
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
''turn off filters
ws.AutoFilterMode = False
End Sub
field:= is an offset and you only have a single column as your range. You want that to be field:=1
You are also using xland you want xlor. Can't have both an empty cell and a cell with ballroom.
.AutoFilter Field:=1, Criteria1:=IsEmpty(rng), Operator:=xlOr, Criteria2:="=*ballroom*"
Thought you have your answer and because of your comment (you want to delete every row which doesn't match your criteria) I adjusted your code to make it easier to read and perform what you actually want it to:
Option Explicit
Sub row_deleter()
Dim lastrow As Long
''setting varibles
'you can use a With ActiveSheet and avoid the use of ws Thought I wouldn't recommend using ActiveSheet unless you attach
'this macro to a button on the sheet itself.
With ActiveSheet
lastrow = .Range("E" & .Rows.Count).End(xlUp).Row
''actual filter function
.UsedRange.AutoFilter Field:=5, Criteria1:="<>", Operator:=xlOr, Criteria2:="<>*ballroom*"
.Range("A2:A" & lastrow).SpecialCells(xlCellTypeVisible).EntireRow.Delete
''turn off filters
.AutoFilterMode = False
End With
End Sub
Related
i need your help on the VBA code :
i would like to make a filter on a database according cells in another sheets
my code is working but make a filter only in one cell. How to filter if the code found all cells from the Range
Please see my code :
Sub test()
Sheets("Dashboard").Select
Dim arr As Variant
'arr = Sheets("Dashboard").Range("B4:B11")
With Sheets("Database")
With .Range("A1:Z" & .Cells(.Rows.Count, "A").End(xlUp).Row)
.AutoFilter 'Turn off any previous filtering
.AutoFilter Field:=1, Criteria1:=Sheets("Dashboard").Range("B4:B11")
End With
End With
End Sub
Thanks for your help
Please, test the next way:
Sub filterByRange()
Dim arr, rng As Range
Set rng = Sheets("Dashboard").Range("B4:B11")
rng.TextToColumns Destination:=rng.cells(1), FieldInfo:=Array(1, 2)
arr = rng.Value
arr = Application.Transpose(Application.Index(arr, 0, 1)) '1D array
With Sheets("Database")
With .Range("A1:Z" & .cells(.Rows.count, "A").End(xlUp).row)
.AutoFilter
.AutoFilter field:=1, Criteria1:=arr, Operator:=xlFilterValues
End With
End With
End Sub
Less is more. I adapted the code provided by #FaneDuru utilising some shortcuts. Please note that when it comes to AutoFilter, there’s (usually) no need to specify the complete range you want to filter – it filters all rows meeting the criteria so last column is irrelevant. As long as the data is contiguous, there’s no need to specify the last row either.
Provided for interest only.
Sub testFilter()
Dim Arr
Arr = Sheets("Dashboard").Range("B4:B11").Value
Arr = Application.Transpose(Application.Index(Arr, 0, 1))
With Sheets("Database").Range("A1").CurrentRegion
.AutoFilter 1, Array(Arr), 7
End With
End Sub
Try this:
Sub SubRangeBasedAutofilter()
'Declarations.
Dim RngCell As Range
Dim RngCriteria As Range
Dim StrCriteria() As String
Dim DblCriteriaCount As Double
'Selecting Dashboard sheet.
Sheets("Dashboard").Select '<-IS THIS NECESSARY?
'Setting RngCriteria.
Set RngCriteria = Sheets("Dashboard").Range("B4:B11")
'Redeclaring StrCriteria() with proper size.
ReDim StrCriteria(Excel.WorksheetFunction.Max(Excel.WorksheetFunction.CountA(RngCriteria) - 1, 1))
'Covering each in RngCriteria.
For Each RngCell In RngCriteria
'Checking if RngCell is not empty.
If RngCell.Value <> "" Then
'Storing the criteria.
StrCriteria(DblCriteriaCount) = "=" & RngCell.Value
DblCriteriaCount = DblCriteriaCount + 1
End If
Next
'Focusing Database sheet.
With Sheets("Database")
'Turning off any eventual autofilter.
.AutoFilterMode = False
'Setting a new autofilter.
With .Range("A1:Z" & .Cells(.Rows.Count, "A").End(xlUp).Row)
.AutoFilter Field:=1, Criteria1:=StrCriteria, Operator:=xlFilterValues
End With
End With
End Sub
I have code which sorts and copies results from one worksheet to another. Sometimes I need to paste copied range to the next blank cell on selected worksheet, for which I need to use ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row.
Worksheets("Wallets").AutoFilterMode = False
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=5, Criteria1:="*TRANSFER*"
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=7, Criteria1:=">0"
Worksheets("Wallets").Range("B2:I" & Worksheets("Wallets").Cells(Rows.Count, 1).End(xlUp).Row).Copy
Worksheets("Transfers").Cells(Worksheets("Transfers").Cells(Rows.Count, 1).End(xlUp).Row, 1).Offset(1, 0).PasteSpecial Paste:=xlPasteValue
Worksheets("Wallets").AutoFilterMode = False
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=5, Criteria1:="*EXCHANGE*"
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=7, Criteria1:=">0"
Worksheets("Wallets").Range("B2:I" & Worksheets("Wallets").Cells(Rows.Count, 1).End(xlUp).Row).Copy
Worksheets("Transfers").Cells(Worksheets("Transfers").Cells(Rows.Count, 1).End(xlUp).Row, 1).Offset(1, 0)..PasteSpecial Paste:=xlPasteValues
I was thinking about changing code so i can replace this part more easily if I need to use other column for some worksheets for example. Is there any way to make variable recalculate each time it used in sub? Part of code below just saves first result and uses it, but I need to update row count number it for each worksheet which is currently used(perferably without using Worksheets.Select).
Sub Sort_Wallets()
Dim x As Long
x = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Wallets").AutoFilterMode = False
Worksheets("Wallets").Select
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=5, Criteria1:="*TRANSFER*"
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=7, Criteria1:=">0"
Worksheets("Wallets").Range("B2:I" & x).Copy
Worksheets("Transfers").Select
Worksheets("Transfers").Cells(x, 1).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
Worksheets("Wallets").AutoFilterMode = False
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=5, Criteria1:="*EXCHANGE*"
Worksheets("Wallets").Range("$A$1:$J10000").AutoFilter Field:=7, Criteria1:=">0"
Worksheets("Wallets").Range("B2:I" & x).Copy
Worksheets("Transfers").Cells(x, 1).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
End Sub
If you are looping through worksheets you can, but not if you are only using two worksheets. You will need to specify the worksheet. You are using x as the last row in each case and I doubt that is true. Why set J10000 if you are going to find the last row? Also, it looks like you only want to copy the visible cells after you filter. You need to specify that you only want the visible cells. It is easier to follow your code if you Set the variables, ranges and worksheets so as not to repeat long lines. Here is an example of what I just said using your code. There may even be a better solution, but this is more readable than what you have.
Sub Sort_Wallets()
Dim destlr As Long
Dim sourcelr As Long
Dim wk1 As Worksheet
Dim wk2 As Worksheet
Dim FiltRng As Range
Set wk1 = ThisWorkbook.Worksheets("Wallets")
Set wk2 = ThisWorkbook.Worksheets("Transfers")
destlr = wk2.Cells(Rows.Count, 1).End(xlUp).Row
sourcelr = wk1.Cells(Rows.Count, 1).End(xlUp).Row
Set FiltRng = wk1.Range(wk1.Cells(1, 1), wk1.Cells(sourcelr, 10))
wk1.AutoFilterMode = False
FiltRng.AutoFilter Field:=5, Criteria1:="*TRANSFER*"
FiltRng.AutoFilter Field:=7, Criteria1:=">0"
wk1.Range("B2:I" & sourcelr).SpecialCells(xlCellTypeVisible).Copy
wk2.Cells(destlr, 1).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
wk1.AutoFilterMode = False
FiltRng.AutoFilter Field:=5, Criteria1:="*EXCHANGE*"
FiltRng.AutoFilter Field:=7, Criteria1:=">0"
wk1.Range("B2:I" & sourcelr).SpecialCells(xlCellTypeVisible).Copy
wk2.Cells(destlr, 1).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
End Sub
Assuming you're using your worksheets like data tables, use "tables". For each table of data, highlight it and "Insert Table", and then go into the table ribbon (available only when the cursor is within that table) and change the name of your table from whatever it is ("Table5") to something that makes sense to you.
In VBA, these are called ListObjects. As long as you know the names of these tables, you can get them with the following code:
'Returns the specified object from a collection
'Returns Nothing if the value in the collection doesn't exist.
'Throws no errors
Private Function GetFromCollection(col As Collection, sKey As String) As Object
On Error Resume Next
Set GetFromCollection = col.item(sKey)
Err.Clear
End Function
Public Function GetListObjectFromWorkbook(sTableName As String, Optional bRecache As Boolean = False) As ListObject
Static bInitialized As Boolean
Static col As Collection
Dim lo As ListObject
Dim sht As Worksheet
If bRecache Or Not bInitialized Then
Set col = New Collection
For Each sht In Sheets
For Each lo In sht.ListObjects
col.Add lo, lo.Name
Next lo
Next sht
bInitialized = True
End If
Set GetListObjectFromWorkbook = GetFromCollection(col, sTableName)
End Function
From there, you don't need to know where the last row is! Adding a new row is:
Dim listrow As ListRow
Set listrow = GetListObjectFromWorkbook(sTableName).ListRows.Add
and you can manipulate the values of that new ListRow via listrow.Range
FYI: You can sort ListObjects, too. See the VB code in https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.tools.excel.listobject.sort?view=vsto-2017
i'm using the following piece of code to exclude nulls along with "(blank)" values. unfortunately, it only seems to be removing the nulls. please help
ActiveSheet.AutoFilter field:=1, Criteria1:="<>" & "", Operator:=xlAnd, Criteria2:="<>(blank)"
Something like:
Option Explicit
Sub testFilter()
Dim WS As Worksheet: Set WS = Worksheets("sheet1")
Dim R As Range: Set R = WS.Cells(1, 1).CurrentRegion
If WS.AutoFilterMode = True Then _
WS.AutoFilter.ShowAllData
R.AutoFilter Field:=1, Criteria1:="<>", Operator:=xlAnd, Criteria2:="<>(blank)"
End Sub
Note:
You should be using the AutoFilter method of the Range object, not the Autofilter property of the Worksheet object as you show in your code.
I am trying to copy the values from one Excel sheet into another using Filter option. For example I have used only ten records, but in real time I am not sure the data that will be present. Also, I need to know the first cell value after a filter. For example, if I use filter the first value is reflecting as B4 and next time it is showing B6. I need to select that also dynamically using macro.
ActiveSheet.Range("$A$1:$BG$10").AutoFilter Field:=2, Criteria1:="2"
Range("B5:BG5").Select
The above code should be modified. Instead of $BG$10 it should be the number of rows, then Instead of B5:BG5 it must be the first cell after filter.
Try this:
Dim rngToFilter As Range
With ActiveSheet
.AutoFilterMode = False 'to make sure no filter is applied yet
Set rngToFilter = .Range("A1", .Range("BG" & Rows.Count).End(xlUp)) 'set the dynamic range
rngToFilter.AutoFilter Field:=2, Criteria1:="2" 'apply the filter
rngToFilter.Resize(.Range("BG" & Rows.Count).End(xlUp).Row - 1).Offset(1, 0).SpecialCells(xlCellTypeVisible).Select 'Offset 1 row to exclude the header, resize to select the first row only.
End With
Above code selects all the items that are filtered.
I you want so select only the 1st item filtered, then use below.
Sub Sample()
Dim rngToFilter As Range, rngFilter As Range
Dim i As Integer
With ActiveSheet
.AutoFilterMode = False 'to make sure no filter is applied yet
Set rngToFilter = .Range("A1", .Range("BG" & Rows.Count).End(xlUp)) 'set the dynamic range
rngToFilter.AutoFilter Field:=2, Criteria1:="2" 'apply the filter
Set rngFilter = rngToFilter.Resize(.Range("BG" & Rows.Count).End(xlUp).Row - 1).Offset(1, _
0).SpecialCells(xlCellTypeVisible)
rngToFilter.Resize(.Range("BG" & Rows.Count).End(xlUp).Row - _
(rngFilter.Cells.Count / rngFilter.Columns.Count)).Offset(1, _
0).SpecialCells(xlCellTypeVisible).Select
End With
End Sub
No error handler yet.
I leave it to you. :D
Try following code:
Sub test()
Dim lastRow As Long, firstVisibleRow As Long
ActiveSheet.AutoFilterMode = False
'find last non empty row number in column A'
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
'apply filter'
Range("$A$1:$BG$" & lastRow).AutoFilter Field:=2, Criteria1:="2"
On Error GoTo errHandler
'find first visible row number in the filtered range, if there is no rows matching the filter criteria, we'll get message from the MsgBox'
firstVisibleRow = Range("$A$2:$BG$" & lastRow).SpecialCells(xlCellTypeVisible).Row
On Error GoTo 0
'select range'
Range("B" & firstVisibleRow & ":BG" & firstVisibleRow).Select
Exit Sub
errHandler:
MsgBox "There is no rows matching the filter criteria"
End Sub
I am trying to apply an autofilter in VBA for three different criterias in the same field. Once I have applied the filter I would like to find all those cells that are blank, can anyone advise?
Sub ApplyAutoFiler()
Dim ws As Worksheet
Dim I, j, NumberOfErrors As Long
IsErrors = False
Set ws = Sheets("Assessments")
NumberOfErrors = 0
Dim Z As Range
Set Z = Cells(4, 3).EntireColumn.Find("*", SearchDirection:=xlPrevious)
If Not Z Is Nothing Then
NumberOfRows = Z.Row
End If
For I = 4 To NumberOfRows
With ws
.AutoFilterMode = False
.Range("W4:AA4").AutoFilter Field:=1, Criteria1:=Array("A", "B", "C"), Operator:=xlFilterValues
.Cells.SpecialCells(xlCellTypeBlanks).Interior.Color = 65535
.AutoFilterMode = False
End With
Next I
End Sub
I ended up doing this as a nested if statement
If Range("W" & i).Value = "A" Or Range("W" & i).Value = "B" Or Range("W" & i).Value = "C" Then
If Range("AD" & i).Value = "" Then
Range("AD" & CStr(i)).Interior.ColorIndex = 3
NumberOfErrors = NumberOfErrors + 1
End If
End If
This seemed to get me close (it also assumes you have a worksheet called "Assessments"):
Sub ApplyAutoFiler()
Dim ws As Worksheet
Set ws = Sheets("Assessments")
With ws
.AutoFilterMode = False
.Range("A:AZ").AutoFilter Field:=23, Criteria1:=Array("a", "b", "c"), Operator:=xlFilterValues
.Cells.SpecialCells(xlCellTypeBlanks).Interior.Color = 65535
.AutoFilterMode = False
End With
End Sub
I know this treads had been quite long. But just want to share. To filter out blank cells, you could use autofilter using the following criteria:
Worksheets("sheet name").Range("A1").autoFilter Field:=18, Criteria1:=(Blanks)
"Field" refers to the column numbers. As for "Criteria1", it can be either
Criteria1:=(Blanks)
or
Criteria1:="="
or
Criteria1:=""
Something I just discovered today about filtering for blanks using VBA code. Be sure to include this in ALL code where you need to have blank cells:
' Get Rows with blanks
WorkRange.AutoFilter Field:=1, Criteria1:="=", Operator:=xlOr, Criteria2:="=" & ""
' Hides Rows with blanks ... same idea with the "<>" for operator
WorkRange.AutoFilter Field:=1, Criteria1:="<>", Operator:=xlOr, Criteria2:="<>" & ""
The first criteria gets true blank cells and those cells with hidden/non-printable characters, the 2nd criteria gets those cells containing an empty string. Excel user-interface handles this nicely, but VBA code requires both criteria.
This undocumented caveat just cost me several hours of debugging, not to mention a few choice words from my manager about "I thought we were removing the blanks from these columns..."
Just thought I would share, in the hopes of saving you all some headaches.
You don't need VBA for this. You can use Conditional Formatting for this. See this example
In the CF rule, set this formula
=AND($AA5="",OR($W5="a",$W5="b",$W5="c"))
ScreenShot
If you still want VBA then see this
Sub Sample()
Dim blnkRange As Range, rng As Range, aCell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Assessments")
With ws
'~~> Sample range for testing purpose
Set rng = .Range("W4:AA11")
.AutoFilterMode = False
With rng
'~~> Filter on "a","b","c"
.AutoFilter Field:=1, Criteria1:=Array("a", "b", "c"), Operator:=xlFilterValues
'~~> Then filter on blanks on Col AA
.AutoFilter Field:=5, Criteria1:="="
'~~> Using offset. Assuming that Row 4 has headers
Set blnkRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible).Cells
End With
.AutoFilterMode = False
End With
'~~> This will give you the blank cells in Col AA
If Not blnkRange Is Nothing Then
For Each aCell In blnkRange
'~~> Color the blank cells red in Col AA
If aCell.Column = 27 Then aCell.Interior.ColorIndex = 3
Next
End If
End Sub