autofilter ; Uses and best practices
Autofilter ultimate goal is to provide in the quickest way possible data mining from hundreds or thousands of rows data in order to get the attention in the items we want to focus on. It can receive parameters such as “text/values/colors” and they can be stacked among columns. You may connect up to 2 criteria per column based in logical connectors and sets of rules. Remark: Autofilter works by filtering rows, there is no Autofilter to filter columns (at least not natively).
Smartfilter!
Section titled “Smartfilter!”Problem situation
Warehouse administrator has a sheet (“Record”) where every logistics movement performed by the facility is stored, he may filter as needed, although, this is very time consuming and he would like to improve the process in order to calculate inquiries faster, for example: How many “pulp” do we have now (in all racks)? How many pulp do we have now (in rack #5)? Filters are a great tool but, they are somewhat limited to answer these kind of question in matter of seconds.

Macro solution:
The coder knows that autofilters are the best, fast and most reliable solution in these kind of scenarios since the data exists already in the worksheet and the input for them can be obtained easily -in this case, by user input-.
The approach used is to create a sheet called “SmartFilter” where administrator can
easily filter multiple data as needed and calculation will be performed instantly as well.
He uses 2 modules and the Worksheet_Change event for this matter
Code For SmartFilter Worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)Dim ItemInRange As RangeConst CellsFilters As String = "C2,E2,G2" Call ExcelBusy For Each ItemInRange In Target If Not Intersect(ItemInRange, Range(CellsFilters)) Is Nothing Then Call Inventory_Filter Next ItemInRange Call ExcelNormalEnd SubCode for module 1, called “General_Functions”
Sub ExcelNormal() With Excel.Application .EnableEvents = True .Cursor = xlDefault .ScreenUpdating = True .DisplayAlerts = True .StatusBar = False .CopyObjectsWithCells = True End WithEnd SubSub ExcelBusy() With Excel.Application .EnableEvents = False .Cursor = xlWait .ScreenUpdating = False .DisplayAlerts = False .StatusBar = False .CopyObjectsWithCells = True End WithEnd SubSub Select_Sheet(NameSheet As String, Optional VerifyExistanceOnly As Boolean) On Error GoTo Err01Select_Sheet Sheets(NameSheet).Visible = True If VerifyExistanceOnly = False Then ' 1. If VerifyExistanceOnly = False Sheets(NameSheet).Select Sheets(NameSheet).AutoFilterMode = False Sheets(NameSheet).Cells.EntireRow.Hidden = False Sheets(NameSheet).Cells.EntireColumn.Hidden = False End If ' 1. If VerifyExistanceOnly = False If 1 = 2 Then '99. If errorErr01Select_Sheet: MsgBox "Err01Select_Sheet: Sheet " & NameSheet & " doesn't exist!", vbCritical: Call ExcelNormal: On Error GoTo -1: End End If '99. If errorEnd SubFunction General_Functions_Find_Title(InSheet As String, TitleToFind As String, Optional InRange As Range, Optional IsNeededToExist As Boolean, Optional IsWhole As Boolean) As RangeDim DummyRange As Range On Error GoTo Err01General_Functions_Find_Title If InRange Is Nothing Then ' 1. If InRange Is Nothing Set DummyRange = IIf(IsWhole = True, Sheets(InSheet).Cells.Find(TitleToFind, LookAt:=xlWhole), Sheets(InSheet).Cells.Find(TitleToFind, LookAt:=xlPart)) Else ' 1. If InRange Is Nothing Set DummyRange = IIf(IsWhole = True, Sheets(InSheet).Range(InRange.Address).Find(TitleToFind, LookAt:=xlWhole), Sheets(InSheet).Range(InRange.Address).Find(TitleToFind, LookAt:=xlPart)) End If ' 1. If InRange Is Nothing Set General_Functions_Find_Title = DummyRange If 1 = 2 Or DummyRange Is Nothing Then '99. If errorErr01General_Functions_Find_Title: If IsNeededToExist = True Then MsgBox "Err01General_Functions_Find_Title: Ttile '" & TitleToFind & "' was not found in sheet '" & InSheet & "'", vbCritical: Call ExcelNormal: On Error GoTo -1: End End If '99. If errorEnd FunctionCode for module 2, called “Inventory_Handling”
Const TitleDesc As String = "DESCRIPTION"Const TitleLocation As String = "LOCATION"Const TitleActn As String = "ACTION"Const TitleQty As String = "QUANTITY"Const SheetRecords As String = "Record"Const SheetSmartFilter As String = "SmartFilter"Const RowFilter As Long = 2Const ColDataToPaste As Long = 2Const RowDataToPaste As Long = 7Const RangeInResult As String = "K1"Const RangeOutResult As String = "K2"Sub Inventory_Filter()Dim ColDesc As Long: ColDesc = General_Functions_Find_Title(SheetSmartFilter, TitleDesc, IsNeededToExist:=True, IsWhole:=True).ColumnDim ColLocation As Long: ColLocation = General_Functions_Find_Title(SheetSmartFilter, TitleLocation, IsNeededToExist:=True, IsWhole:=True).ColumnDim ColActn As Long: ColActn = General_Functions_Find_Title(SheetSmartFilter, TitleActn, IsNeededToExist:=True, IsWhole:=True).ColumnDim ColQty As Long: ColQty = General_Functions_Find_Title(SheetSmartFilter, TitleQty, IsNeededToExist:=True, IsWhole:=True).ColumnDim CounterQty As LongDim TotalQty As LongDim TotalIn As LongDim TotalOut As LongDim RangeFiltered As Range Call Select_Sheet(SheetSmartFilter) If Cells(Rows.Count, ColDataToPaste).End(xlUp).Row > RowDataToPaste - 1 Then Rows(RowDataToPaste & ":" & Cells(Rows.Count, "B").End(xlUp).Row).Delete Sheets(SheetRecords).AutoFilterMode = False If Cells(RowFilter, ColDesc).Value <> "" Or Cells(RowFilter, ColLocation).Value <> "" Or Cells(RowFilter, ColActn).Value <> "" Then ' 1. If Cells(RowFilter, ColDesc).Value <> "" Or Cells(RowFilter, ColLocation).Value <> "" Or Cells(RowFilter, ColActn).Value <> "" With Sheets(SheetRecords).UsedRange If Sheets(SheetSmartFilter).Cells(RowFilter, ColDesc).Value <> "" Then .AutoFilter Field:=General_Functions_Find_Title(SheetRecords, TitleDesc, IsNeededToExist:=True, IsWhole:=True).Column, Criteria1:=Sheets(SheetSmartFilter).Cells(RowFilter, ColDesc).Value If Sheets(SheetSmartFilter).Cells(RowFilter, ColLocation).Value <> "" Then .AutoFilter Field:=General_Functions_Find_Title(SheetRecords, TitleLocation, IsNeededToExist:=True, IsWhole:=True).Column, Criteria1:=Sheets(SheetSmartFilter).Cells(RowFilter, ColLocation).Value If Sheets(SheetSmartFilter).Cells(RowFilter, ColActn).Value <> "" Then .AutoFilter Field:=General_Functions_Find_Title(SheetRecords, TitleActn, IsNeededToExist:=True, IsWhole:=True).Column, Criteria1:=Sheets(SheetSmartFilter).Cells(RowFilter, ColActn).Value 'If we don't use a filter we would need to use a cycle For/to or For/Each Cell in range 'to determine whether or not the row meets the criteria that we are looking and then 'save it on an array, collection, dictionary, etc 'IG: For CounterRow = 2 To TotalRows 'If Sheets(SheetSmartFilter).Cells(RowFilter, ColDesc).Value <> "" and Sheets(SheetRecords).cells(CounterRow,ColDescInRecords).Value= Sheets(SheetSmartFilter).Cells(RowFilter, ColDesc).Value then 'Redim Preserve MyUnecessaryArray(UnecessaryNumber) ''Save to array: (UnecessaryNumber)=MyUnecessaryArray. Or in a dictionary, etc. At the end, we would transpose this values into the sheet, at the end 'both are the same, but, just try to see the time invested on each logic. If .Cells(1, 1).End(xlDown).Value <> "" Then Set RangeFiltered = .Rows("2:" & Sheets(SheetRecords).Cells(Rows.Count, "A").End(xlUp).Row).SpecialCells(xlCellTypeVisible) 'If it is not <>"" means that there was not filtered data! If RangeFiltered Is Nothing Then MsgBox "Err01Inventory_Filter: No data was found with the given criteria!", vbCritical: Call ExcelNormal: End RangeFiltered.Copy Destination:=Cells(RowDataToPaste, ColDataToPaste) TotalQty = Cells(Rows.Count, ColQty).End(xlUp).Row For CounterQty = RowDataToPaste + 1 To TotalQty If Cells(CounterQty, ColActn).Value = "In" Then ' 2. If Cells(CounterQty, ColActn).Value = "In" TotalIn = Cells(CounterQty, ColQty).Value + TotalIn ElseIf Cells(CounterQty, ColActn).Value = "Out" Then ' 2. If Cells(CounterQty, ColActn).Value = "In" TotalOut = Cells(CounterQty, ColQty).Value + TotalOut End If ' 2. If Cells(CounterQty, ColActn).Value = "In" Next CounterQty Range(RangeInResult).Value = TotalIn Range(RangeOutResult).Value = -(TotalOut) End With End If ' 1. If Cells(RowFilter, ColDesc).Value <> "" Or Cells(RowFilter, ColLocation).Value <> "" Or Cells(RowFilter, ColActn).Value <> ""End Sub
Testing and results:
As we saw in the previous image, this task has been achieved easily. By using autofilters a solution was provided that just takes seconds to compute, is easy to explain to the user -since s/he is familiar with this command- and took a few lines to the coder.
Remarks
Section titled “Remarks”‘To use Autofilter within VBA we need to call with at least the following parameters:
Sheet(“MySheet”).Range(“MyRange”).Autofilter Field=(ColumnNumberWithin”MyRange”ToBeFilteredInNumericValue) Criteria1:= “WhatIWantToFilter”
‘There are plenty of examples either on the web or here at stackoverflow