VBA to filter result and paste

hwong8848

New Member
Joined
Oct 9, 2022
Messages
19
Office Version
  1. 365
Platform
  1. Windows
Hi all, I had been using the function "Filter" and "FIND" to get the data I need in some range. However, since it seems to be quite slow (correct me if Im wrong)

I have attached the sheet as example, hope there is a way to filter using VBA and hardcoded them rather than having formulas.

Book1
ABCDEFGHIJ
1No.AmountTypeYearType 1AXA
21488584.8ING2017Type 2ING
32250632.5Barclays1942Type 3Barclays
43457570.7Barclays Inc2008
54788922.4AXA2001Year 11927
65893828.3Barclays Inc1927Year 22000
76702071.8Barclays Inc1977Year 31885
87235300.4Barclays1911
9816744.72AXA Asia1917List of data below
109431784.2Barclays Inc2005No.AmountTypeYear
1110960657.1Barclays Inc19325893828.3Barclays Inc1927
1211367964.8AXA Asia201716231481.3Barclays1885
1312651444.6AXA201140672836.9ING2000
1413680266.1AXA Asia195255517833.8AXA2000
1514582452.5AXA Asia198861135398.3AXA Asia2000
1615454502AXA Asia1905
1716231481.3Barclays1885
1817864936AXA1969
1918151017.6AXA Asia1968
2019857505.8ING2011
2120621567.7Barclays1997
2221441127.6AXA Asia1932
2322174814.9AXA Asia1944
2423224838.3Barclays Inc1945
2524234594.6AXA1877
2625893053.4Barclays1966
2726260026.1AXA1891
2827866069.4ING1880
2928398682.9ING1888
3029538950.4Barclays Inc1996
3130679969.3Barclays1896
3231378884Barclays Inc1984
3332355523.3Barclays1876
3433171003.2Barclays Inc2001
3534354718.8Barclays Inc1978
3635415886.7Barclays Inc1942
3736619948.1AXA Asia2012
3837118869.7Barclays Inc1891
3938120148.5Barclays1877
4039665417.9Barclays1913
4140672836.9ING2000
4241178061.4Barclays1956
4342981607.7Barclays Inc1890
4443667142.6Barclays1994
4544823963.5Barclays Inc1870
464567132.63Barclays Inc1920
4746589131.6Barclays Inc2008
4847172846.9ING1875
4948923918ING1937
504913007.48Barclays Inc1973
5150507918.4Barclays Inc1925
5251789229.9Barclays Inc1941
5352625808.8ING1975
5453154092.7Barclays1990
5554552473.8AXA1999
5655517833.8AXA2000
5756611265.8AXA Asia1912
5857407144.4Barclays Inc1926
5958544767.8Barclays Inc1958
6059228377.3Barclays Inc1954
6160545213.3Barclays Inc1994
6261135398.3AXA Asia2000
6362546073.9AXA1934
6463249206ING2018
6564928358.4Barclays Inc1988
6665790988.8AXA Asia1918
6766931209.6Barclays Inc1882
686791423.89ING1889
6968873575.2AXA1898
7069202411.3ING1959
7170748599.5Barclays1878
7271559973.5AXA1993
7372820930.2AXA1910
7473843185.9Barclays1929
7574723126.2AXA1954
7675193327Barclays2007
7776244339.7ING1950
787761578.2ING1949
7978588266Barclays Inc1942
8079957150.5ING1957
8180500998.3Barclays Inc1970
8281109669.8AXA1948
8382947285.8Barclays Inc2013
8483777129.9AXA Asia1890
8584313658.5Barclays Inc1890
8685418338.4Barclays2017
8786692562.4ING2009
8887389527.8AXA Asia2004
898877174.76AXA1926
9089604184.2AXA Asia1892
9190121492Barclays2006
9291486313.8Barclays1944
9392364265.5AXA Asia1932
9493600225.7Barclays1901
9594436586.4Barclays1939
9695307823.2Barclays Inc2013
9796251716.8AXA1944
9897668885.3AXA1995
9998601553.3AXA Asia2006
10099445976.1AXA Asia2007
101100981655.3ING1961
Data
Cell Formulas
RangeFormula
G11:J15G11=FILTER(A2:D101,((D2:D101=H7)+(D2:D101=H6)+(D2:D101=H5))*(ISNUMBER(FIND(H1,C2:C101))+(ISNUMBER(FIND(H2,C2:C101))+(ISNUMBER(FIND(H3,C2:C101))))))
Dynamic array formulas.



The blue bit is the place where I want the data to be at.
 

Excel Facts

Select all contiguous cells
Pressing Ctrl+* (asterisk) will select the "current region" - all contiguous cells in all directions.
The following assumes that your sheet is exactly as you have provided in your sample, and that there's nothing beyond column J.

VBA Code:
Option Explicit
Sub AdvancedFilter()
    Application.ScreenUpdating = False
    Dim ws As Worksheet
    Set ws = Worksheets("Data")
    
    If WorksheetFunction.CountA(ws.Range("H1:H3")) = 0 Then
        MsgBox "No Type selected - exiting sub"
        Exit Sub
    ElseIf WorksheetFunction.CountA(ws.Range("H5:H7")) = 0 Then
        MsgBox "No Year selected - exiting sub"
        Exit Sub
    End If
    
    Dim c As Range
    For Each c In ws.Range("H1:H3,H5:H7")
        If c = "" Then c = "MISSING DATA"
    Next c
    
    Dim rngList As Range, rngCriteria As Range, rngCopyTo As Range
    Set rngList = ws.Range("A1").CurrentRegion
    
    With ws
        .Range("L1").Resize(, 2).Value = Array("Type", "Year")
        .Range("H1:H3").Copy .Range("L2").Resize(9)
        .Range("H5").Copy .Range("M2,M6,M10")
        .Range("H6").Copy .Range("M3,M7,M8")
        .Range("H7").Copy .Range("M4,M5,M9")
    End With
    
    For Each c In ws.Range("L2", Cells(Rows.Count, "L").End(xlUp))
        c = c & "*"
    Next c
    
    Set rngCriteria = ws.Range("L1").CurrentRegion
    Set rngCopyTo = ws.Range("G10:J10")
    rngList.AdvancedFilter xlFilterCopy, rngCriteria, rngCopyTo
    
    rngCriteria.ClearContents
    Application.ScreenUpdating = True
End Sub
 
Upvote 0
Solution
I took a different apprach ... treated it like a database. There may be some fancy formulas and built-in functions in newer versions of Exce, but I'm on 2016.

You need to create names ranges for DataAnchor, Year, Type and OutputAnchor ... the "anchor" names mean only the top left cell, not the whole range. Paste the FilterMagic code below into a module and run the macro. There is no need to have all the ranges on the same sheet (Year and Type must be on the same sheet). You can have as many YEAR and TYPE rows as you want, just give the range(s) more rows. You can run it manually or you can put the short bit of code below into the sheet module where your YEARS and TYPES ranges are. This will run FilterMagic any time a value is changed in the YEARS or TYPES ranges.

Wit a little modofication, this can work with Excel tables, any number of fields, and any number of additions to the SQL string.

Code to auto run when Year or Type are changed ... put in come module of worksheet containing Year and Type ranges
VBA Code:
Dim booRunChangeEvent As Boolean, booRunning As Boolean
Private Sub Worksheet_Change(ByVal Target As Range)
    If booRunning Then Exit Sub
    If booRunChangeEvent Then booRunning = True: Call FilterMagic
    booRunning = False
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    booRunChangeEvent = Not Application.Intersect(ActiveCell, Range(Range(strName_YearRange), Range(strName_TypeRange))) Is Nothing
End Sub

Main Code
VBA Code:
Option Explicit

Public Const strName_YearRange$ = "\Year"             ' 1 column w Years
Public Const strName_TypeRange$ = "\Type"             ' 1 column w Types
Public Const strName_DataAnchor$ = "\Data"           ' just the top left cell; including headers of where lookup data is
Public Const strName_OutputAnchor$ = "\OutputAnchor" ' just the top left cell; not including headers

Public Sub FilterMagic()
Dim oWb As Workbook, strTmpName$
Dim dbConn As Object, strConn$  'http://www.connectionstrings.com
Dim strSQL$, c As Range, strYr$, strType$, dbRs As Object
    
    Set oWb = ThisWorkbook
    With oWb
        strTmpName = "SafeToDelete_" & Fix(Now() * 10 ^ 8) 'temp name
        .Names.Add strTmpName, Range(strName_DataAnchor).CurrentRegion, True
    End With

    'Make this workbook a database
    Set dbConn = CreateObject("ADODB.Connection"): Set dbRs = CreateObject("ADODB.Recordset")
    strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & oWb.FullName & "';Extended Properties='Excel 12.0 Macro;HDR=YES;IMEX=0';"
    dbConn.Open strConn

    'Base SQL string
    strSQL = "SELECT * FROM " & strTmpName & ";"

    'WHERE YEAR clause
    For Each c In Range(strName_YearRange)
        If c <> Empty And IsNumeric(c) Then strYr = strYr & c & ","
    Next c
    If Len(strYr) > 0 Then strYr = " WHERE YEAR IN (" & Left(strYr, Len(strYr) - 1) & ")"
    strSQL = Replace(strSQL, ";", strYr & ";")

'   'TYPE LIKE clause
    For Each c In Range(strName_TypeRange)
        If c <> Empty Then strType = strType & " or TYPE like '" & c & "%'"
    Next c
    If Len(strType) > 0 Then strType = Right(strType, Len(strType) - 4)
    If Len(strType) > 0 Then If Len(strYr) > 0 Then strType = " AND (" & strType & ")" Else strType = " WHERE (" & strType & ")"
    strSQL = Replace(strSQL, ";", strType & ";")

    'open record set
    dbRs.Open strSQL, strConn
    oWb.Names(strTmpName).Delete
    
    'clear old data and push recordset to worksheet
    With Range(strName_OutputAnchor)
        If .CurrentRegion.Row < .Row Then .CurrentRegion.Offset(1, 0).ClearContents Else .CurrentRegion.ClearContents
        .CopyFromRecordset dbRs
    End With
    
CleanUp:

    dbRs.Close: Set dbRs = Nothing
    dbConn.Close: Set dbConn = Nothing
    Set c = Nothing
    Set oWb = Nothing
    
Exit Sub
    'OTHER SQL CONSTRUCTIONS
    'https://www.devhut.net/advanced-sql-to-connect-with-excel-workbooks/
    'strSQL = "SELECT * FROM DataTable where YEAR in (1927, 2000, 1885)" ''Named range
    'strSQL = "SELECT * FROM [Filter$A1:A100]" 'Range
    'strSQL = "SELECT * FROM [Sheet1$]" ''All the data in a sheet
    'strSQL = "SELECT * FROM [Excel 12.0 XML;HDR=YES;IMEX=1;database=C:\Docs\LTD.xlsx].[SHEETNAME$XX:XX]" ''Refer to second workbook
End Sub
 
Upvote 0

Forum statistics

Threads
1,223,903
Messages
6,175,284
Members
452,630
Latest member
OdubiYouth

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top