Author: Jon von der Heyden
Dated: 20/05/2010
Overview:
This is quite a common question on the forums. The usual answer that follows involves looping through the criteria range, cell-by-cell, testing the condition and if true then delete/cut/copy the record. But one method that is frequently overlooked, and one that tends to be considerably quicker when dealing with larger data ranges (1000's or rows rather than 100's), is to use the AutoFilter method.
With AutoFilter we can display all criteria matching records and delete/cut/copy the records in one hit!
Here are a few rules about AutoFilter that you need to be aware of before we proceed:
-
AutoFilter assumes your data table has field names (column labels).
-
AutoFilter supports up to two custom criteria (per field).
-
The limitation of the amount of entries in the AutoFilter list is 1,000 in excel 2003. If you have more than 1,000 unique values only the first 1,000 items appear. This has been extended to 10,000 in excel 2007+.
-
After the filter is applied excel will only allow you to select up to 8,192 non-contiguous cells. If you attempt to select more you will encounter the following error message: 'The selection is too large'. Therefore if dealing with particularly large ranges and this is a possibility, it is suggested that you sort your data first according to the same field(s) that you wish to apply the criteria to.
Always back-up your workbook before constructing and testing a routine that could alter your data and data structures. The 'Undo' command cannot be used to reverse the actions of a macro!
Please acquaint yourself with any comments in the code as these may provide much of the explanation. Remove the comments from your project when you are comfortable with the methods described; to maintain a tidy sub routine.
Contents:
Example table:
Sheet1
| |
A |
B |
C |
D |
| 1 |
First Name |
Last Name |
Expense Date |
Amount |
| 2 |
John |
Doe |
02/06/2008 |
792.01 |
| 3 |
Mike |
Smith |
16/02/2009 |
848.81 |
| 4 |
Mary |
Edwards |
04/07/2008 |
390.08 |
| 5 |
John |
Phillips |
17/02/2009 |
585.01 |
| 6 |
Jason |
Burns |
19/02/2009 |
810.34 |
| 7 |
Paul |
Wilson |
26/06/2008 |
15.23 |
| 8 |
John |
Doe |
18/05/2008 |
713.09 |
| 9 |
Jason |
Burns |
04/02/2009 |
246.36 |
| 10 |
Susan |
Jarvis |
07/05/2008 |
506.3 |
| 11 |
Paula |
Jones |
05/09/2008 |
705.23 |
| 12 |
John |
Doe |
19/10/2008 |
389.83 |
| 13 |
Mike |
Smith |
05/11/2008 |
796.38 |
| 14 |
Mary |
Edwards |
06/10/2008 |
167.64 |
| 15 |
Jason |
Burns |
01/08/2008 |
943.42 |
This code belongs in a standard module.
This example will filter all records where the First Name equals 'John'.
Option Explicit
'! Written by Jon von der Heyden
'! Excel Design Solutions Ltd
'! www.exceldesignsolutions.com
'! May-2010
'! Excel 2003
Public Sub FilterRecords_1()
Dim rngTable As Range
Dim lngLastRow As Long
Dim xlCalc As XlCalculation
With Application
.ScreenUpdating = False
.EnableEvents = False
xlCalc = .Calculation
.Calculation = xlManual
.EnableCancelKey = xlDisabled
End With
With Sheet1
.AutoFilterMode = False
lngLastRow = .Range("A" & Rows.Count).End(xlUp).Row
Set rngTable = .Range("A1:D" & lngLastRow)
End With
'! The real stuff starts here
With rngTable
.AutoFilter Field:=1, Criteria1:="=John"
'! It's good to check that your filter is returning the _
correct results - so highlight the visible cells
.Offset(1).SpecialCells(12).Interior.ColorIndex = 3
'! Copy the results to the desired location. Comment the _
copy statement if all you want to delete the records
.Offset(1).SpecialCells(12).Copy Destination:=Sheet2.Range("A1")
'! Delete the records (alternatively delete the EntireRow)
.Offset(1).SpecialCells(12).Delete shift:=xlUp
'! Copy then Delete serves as CUT
.AutoFilter
End With
With Application
.EnableCancelKey = xlInterrupt
.Calculation = xlCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
This code belongs in a standard module.
This example will filter all records where the First Name equals 'John' OR 'Mary'.
Option Explicit
'! Written by Jon von der Heyden
'! Excel Design Solutions Ltd
'! www.exceldesignsolutions.com
'! May-2010
'! Excel 2003
Public Sub FilterRecords_2()
Dim rngTable As Range
Dim lngLastRow As Long
Dim xlCalc As XlCalculation
With Application
.ScreenUpdating = False
.EnableEvents = False
xlCalc = .Calculation
.Calculation = xlManual
.EnableCancelKey = xlDisabled
End With
With Sheet1
.AutoFilterMode = False
lngLastRow = .Range("A" & Rows.Count).End(xlUp).Row
Set rngTable = .Range("A1:D" & lngLastRow)
End With
'! The real stuff starts here
With rngTable
.AutoFilter Field:=1, Criteria1:="=John", Operator:=xlOr, Criteria2:="=Mary"
'! It's good to check that your filter is returning the _
correct results - so highlight the visible cells
.Offset(1).SpecialCells(12).Interior.ColorIndex = 3
'! Copy the results to the desired location. Comment the _
copy statement if all you want to delete the records
.Offset(1).SpecialCells(12).Copy Destination:=Sheet2.Range("A1")
'! Delete the records (alternatively delete the EntireRow)
.Offset(1).SpecialCells(12).Delete shift:=xlUp
'! Copy then Delete serves as CUT
.AutoFilter
End With
With Application
.EnableCancelKey = xlInterrupt
.Calculation = xlCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
This code belongs in a standard module.
This example will filter all records where the First Name equals 'John' AND the Last Name equals 'Doe'.
Option Explicit
'! Written by Jon von der Heyden
'! Excel Design Solutions Ltd
'! www.exceldesignsolutions.com
'! May-2010
'! Excel 2003
Public Sub FilterRecords_3()
Dim rngTable As Range
Dim lngLastRow As Long
Dim xlCalc As XlCalculation
With Application
.ScreenUpdating = False
.EnableEvents = False
xlCalc = .Calculation
.Calculation = xlManual
.EnableCancelKey = xlDisabled
End With
With Sheet1
.AutoFilterMode = False
lngLastRow = .Range("A" & Rows.Count).End(xlUp).Row
Set rngTable = .Range("A1:D" & lngLastRow)
End With
'! The real stuff starts here
With rngTable
.AutoFilter Field:=1, Criteria1:="=John"
.AutoFilter Field:=2, Criteria1:="=Doe"
'! It's good to check that your filter is returning the _
correct results - so highlight the visible cells
.Offset(1).SpecialCells(12).Interior.ColorIndex = 3
'! Copy the results to the desired location. Comment the _
copy statement if all you want to delete the records
.Offset(1).SpecialCells(12).Copy Destination:=Sheet2.Range("A1")
'! Delete the records (alternatively delete the EntireRow)
.Offset(1).SpecialCells(12).Delete shift:=xlUp
'! Copy then Delete serves as CUT
.AutoFilter
End With
With Application
.EnableCancelKey = xlInterrupt
.Calculation = xlCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
This code belongs in a standard module.
This example will filter all records where First Name AND Last Names are 'John Doe', 'Mary Edwards', 'Paula Jones'.
Option Explicit
'! Written by Jon von der Heyden
'! Excel Design Solutions Ltd
'! www.exceldesignsolutions.com
'! May-2010
'! Excel 2003
Public Sub FilterRecords_4()
Dim rngTable As Range
Dim lngLastRow As Long
Dim xlCalc As XlCalculation
Dim arrFNames, arrLNames, lngArrItem As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
xlCalc = .Calculation
.Calculation = xlManual
.EnableCancelKey = xlDisabled
End With
With Sheet1
.AutoFilterMode = False
lngLastRow = .Range("A" & Rows.Count).End(xlUp).Row
Set rngTable = .Range("A1:D" & lngLastRow)
End With
'! The real stuff starts here
arrFNames = Array("John", "Mary", "Paula")
arrLNames = Array("Doe", "Edwards", "Jones")
With rngTable
For lngArrItem = LBound(arrFNames) To UBound(arrFNames)
.AutoFilter Field:=1, Criteria1:="=" & arrFNames(lngArrItem), _
Operator:=xlAnd
.AutoFilter Field:=2, Criteria1:="=" & arrLNames(lngArrItem)
'! It's good to check that your filter is returning the _
correct results - so highlight the visible cells
.Offset(1).SpecialCells(12).Interior.ColorIndex = 3
'! Copy the results to the desired location. Comment the _
copy statement if all you want to delete the records
.Offset(1).SpecialCells(12).Copy _
Destination:=Sheet2.Range("A" & Rows.Count).End(xlUp)(1)
'! Delete the records (alternatively delete the EntireRow)
.Offset(1).SpecialCells(12).Delete shift:=xlUp
'! Copy then Delete serves as CUT
.AutoFilter
Next lngArrItem
End With
With Application
.EnableCancelKey = xlInterrupt
.Calculation = xlCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
This code belongs in a standard module.
Filtering dates can be a little more tricky. You will be better off using serial date value criteria rather than date strings. Since serial dates are numbers the typical method is to assign a date value to a Long Integer type variable.
Option Explicit
'! Written by Jon von der Heyden
'! Excel Design Solutions Ltd
'! www.exceldesignsolutions.com
'! May-2010
'! Excel 2003
Public Sub FilterRecords_5()
Dim rngTable As Range
Dim lngLastRow As Long
Dim xlCalc As XlCalculation
Dim lngStartDate As Long, lngEndDate As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
xlCalc = .Calculation
.Calculation = xlManual
.EnableCancelKey = xlDisabled
End With
With Sheet1
.AutoFilterMode = False
lngLastRow = .Range("A" & Rows.Count).End(xlUp).Row
Set rngTable = .Range("A1:D" & lngLastRow)
End With
lngStartDate = DateSerial(2008, 7, 1)
lngEndDate = DateSerial(2008, 10, 30)
'! The real stuff starts here
With rngTable
.AutoFilter Field:=3, Criteria1:=">=" & lngStartDate, _
Operator:=xlOr, Criteria2:="<=" & lngEndDate
'! It's good to check that your filter is returning the _
correct results - so highlight the visible cells
.Offset(1).SpecialCells(12).Interior.ColorIndex = 3
'! Copy the results to the desired location. Comment the _
copy statement if all you want to delete the records
.Offset(1).SpecialCells(12).Copy Destination:=Sheet2.Range("A1")
'! Delete the records (alternatively delete the EntireRow)
.Offset(1).SpecialCells(12).Delete shift:=xlUp
'! Copy then Delete serves as CUT
.AutoFilter
End With
With Application
.EnableCancelKey = xlInterrupt
.Calculation = xlCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
| Symbol |
Means |
| "=" |
Blanks |
| "<>" |
Non-blanks |
| "=" & Criteria |
Equal To |
| "<>" & Criteria |
Does NOT Equal To |
| ">" & Criteria |
Greater Than |
| "<" & Criteria |
Less Than |
| "<=" & Criteria |
Less Than OR Equal To |
| ">=" & Criteria |
Greater Than OR Equal To |
| "=*" & Criteria |
Begins With |
| "<>*" & Criteria |
Does NOT Begin With |
| "=" & Criteria & "*" |
Ends With |
| "<>" & Criteria & "*" |
Does NOT End With |
| "=*" & Criteria & "*" |
Contains |
| "<>*" & Criteria & "*" |
Does NOT Contain |
Note - AutoFilter criteria is case insensitive.
See Also:
External References: