Forum Discussion
My VBA copies row if cell NOTBLANK but I need target columns in specific order (Code in post)
- Apr 26, 2024
Kenneth Green The <> operator on its own will only work if the cells in column K are truly blank. Since it's not working for you, I'm guessing the cells contain zero-length strings, most likely the result of a formula returning "". In this case, you can try using a formula as the criteria. There are 3 rules when using formulas in the criteria range:
- No heading (or use a custom heading not found in the data range, ie: "Criteria1").
- The formula must result in True or False.
- The formula should reference the first row of the data range.
So, in the "AdvFilter" worksheet, delete the heading in cell A1 (or use Criteria1 as the heading), then try either one of the following formulas in cell A2:
='Track Data'!K2<>"" //OR =TRIM('Track Data'!K2)<>"" //OR =LEN('Track Data'!K2)>0
Formula Criteria Example
To address the Advanced Filter results lingering afterwards, which can significantly increase the size of the file when dealing with large amounts of data, just add one line of code to clear the results (rgResults.Offset(1).ClearContents), immediately after the line of code that copies the results to an array:
'Copy the results to an array Dim rgResults As Range, n As Long Set rgResults = wsFilter.Range("A5").CurrentRegion n = rgResults.Rows.Count - 1 If n < 1 Then GoTo CleanUp Dim arr As Variant arr = rgResults.Offset(1).Resize(n).Value rgResults.Offset(1).ClearContents
If you have any other questions, let me know. Cheers!
Kenneth Green If speed and efficiency is what you're looking for, Advanced Filter might be the solution...
Advanced Filter can be used to filter non-blank cells for a given column and copy the results to a new location, outputting only the columns you want to be returned, in whatever order you choose. Since the end result for your described scenario is to append the filtered data to another worksheet, an intermediary worksheet is required, as Advanced Filter cannot append its results directly to an existing dataset. The code for this is minimal, though, and allows you to copy the filtered results in one shot, rather than looping through each row individually.
The setup for the intermediary worksheet would be as follows:
- insert a new worksheet and rename it "AdvFilter"
- in cell A1, input the column header for column K, exactly as it appears in your "Track Data" worksheet
- in cell A2, type the not equal to operator, <>
- in row 5, starting in column A, type the column headers for each of the columns you want to be included in the filtered results, in the order you want them to be returned (again, make sure they are exactly the same as the column headers used in the source table)
The setup should look something like this (change the header labels to match the actual column labels used in the "Track Data" worksheet):
Advanced Filter Setup
Range A1:A2 is the [CriteriaRange], and range A5:H5 is the [CopyToRange]. The code to run Advanced Filter and append the results to the "Titles Data" worksheet would look something like this:
Option Explicit
Sub CopyRowsWithData()
On Error GoTo ErrorHandler
'Turn off application settings
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'Filter the source data to an intermediary worksheet
Dim wsSource As Worksheet, wsFilter As Worksheet
Set wsSource = Sheets("Track Data")
Set wsFilter = Sheets("AdvFilter")
Call AdvFilter(wsSource.Range("A1").CurrentRegion, wsFilter.Range("A1").CurrentRegion, wsFilter.Range("A5"))
'Copy the results to an array
Dim rgResults As Range, n As Long
Set rgResults = wsFilter.Range("A5").CurrentRegion
n = rgResults.Rows.Count - 1
If n < 1 Then GoTo CleanUp
Dim arr As Variant
arr = rgResults.Offset(1).Resize(n).Value
'Write the results to the destination worksheet
Dim wsOutput As Worksheet
Set wsOutput = Sheets("Titles Data")
n = wsOutput.Cells(wsOutput.Rows.Count, 1).End(xlUp).Row + 1
wsOutput.Cells(n, 1).Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
CleanUp:
'Turn on application settings
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox Err.Description, vbExclamation, "Runtime Error: " & Err.Number
Err.Clear
GoTo CleanUp
End Sub
Private Sub AdvFilter(sourceRng As Range, criteriaRng As Range, outputRng As Range, Optional optUnique As Boolean)
'Clear the previous search results
outputRng.CurrentRegion.Offset(1).ClearContents
'Output the new search results
On Error Resume Next
sourceRng.AdvancedFilter xlFilterCopy, criteriaRng, outputRng.CurrentRegion, optUnique
End Sub
This is just an example, and the above code can be easily adapted for a wide variety of scenarios. For more information on Advanced Filter in VBA, check out: https://excelmacromastery.com/vba-advanced-filter/
- Kenneth GreenApr 26, 2024Brass Contributordjclements Thank you for taking the time to write and explain this code which I really do appreciate.
It is so much faster than other code I have tried and I do mean fast.
To filter 41000 rows of data in the Tracks Data worksheet, it took less that a second.
There is an interesting thing happening that I have spent the last couple of hours trying to cure but with out any success.
I set up the AdvFilter sheet exactly as you described but when I use the criteria "<>" it does not filter the results at all and just copies everything first to the AdvFilter sheet and then in to the Titles data sheet.
It does not clear the data it had copied in to AdvFilter which almost doubles the size of the Excel file.
If I was to use something that I know will appear in Column K as the filter "M+S" it filters that perfectly, the for several other text that I know will be in that column.
It just will not filter it using <> which is strange because it should.- djclementsApr 26, 2024Bronze Contributor
Kenneth Green The <> operator on its own will only work if the cells in column K are truly blank. Since it's not working for you, I'm guessing the cells contain zero-length strings, most likely the result of a formula returning "". In this case, you can try using a formula as the criteria. There are 3 rules when using formulas in the criteria range:
- No heading (or use a custom heading not found in the data range, ie: "Criteria1").
- The formula must result in True or False.
- The formula should reference the first row of the data range.
So, in the "AdvFilter" worksheet, delete the heading in cell A1 (or use Criteria1 as the heading), then try either one of the following formulas in cell A2:
='Track Data'!K2<>"" //OR =TRIM('Track Data'!K2)<>"" //OR =LEN('Track Data'!K2)>0
Formula Criteria Example
To address the Advanced Filter results lingering afterwards, which can significantly increase the size of the file when dealing with large amounts of data, just add one line of code to clear the results (rgResults.Offset(1).ClearContents), immediately after the line of code that copies the results to an array:
'Copy the results to an array Dim rgResults As Range, n As Long Set rgResults = wsFilter.Range("A5").CurrentRegion n = rgResults.Rows.Count - 1 If n < 1 Then GoTo CleanUp Dim arr As Variant arr = rgResults.Offset(1).Resize(n).Value rgResults.Offset(1).ClearContents
If you have any other questions, let me know. Cheers!
- Kenneth GreenMay 03, 2024Brass Contributor
Thank you everyone for all of your kind replies and I do appreciate them all.
djclements you were correct and where formulas that were returning blank, Excel had inserted an apostrophe in those cells.
I cured this by having a line of VBA that removes them.
Thank you for this tip.