Tận dụng bộ lọc AutoFilter và AdvancedFilter với hàm UDF nhanh chóng

Chia sẻ bởi:hands
★★★★★
Quảng cáo

HÀM UDF AutoFilter AdvFilter bổ trợ tận dụng hai bộ lọc AutoFilter và AdvancedFilter

Hôm nay tôi chia sẻ với các bạn hàm có thể gọi hai bộ lọc mà Application Excel hỗ trợ trong VBA hoặc phải cài đặt bằng tay trong Ribbon khá rối, thì nay đã có hàm bổ trợ này giúp các bạn thao tác gọn gàng và nhanh hơn để lọc dữ liệu mà các bạn cần hiệu quả hơn.

HƯỚNG DẪN:
Phương pháp viết hàm mới nên cách sử dụng hàm cũng đặc biệt khác với các hàm thông thường.

1. AutoFilter: là hàm bổ trợ cho phương thức AutoFilter của Range trong Application Excel
=AutoFilter(CurrentCells,FilterCells, Parameters())

1

CurrentCells
Vùng cần trả dữ liệu

2

FilterCells
Vùng đặt bộ lọc

3

Parameters()
Các đối số cài đặt cho bộ lọc

Hàm bổ trợ cho Hàm AutoFilter
Với các ký tự aft… là các hàm bổ trợ để cài đặt đối số để thực hiện lọc

aftField(1)
Giá trị
Cài đặt Field

aftCriteria1(">=1")
Giá trị
Đặt điều kiện lọc thứ nhất

aftCriteria2("<=10")
Có/Không
Đặt điều kiện lọc thứ hai

aftDisibleDropDown()

Không hiển thị nút lọc trên trang tính

aftSubField(1)
Giá trị
Cài đặt SubField

Ví dụ gõ hàm: =AutoFilter(A1:C1000,A1:A1000,aftCriteria1(">=1") )

Hàm bổ trợ Sắp xếp cho Hàm AutoFilter
=FilterSort(Parameters())
Với các ký tự aftSort… là các hàm bổ trợ để cài đặt đối số để thực hiện Sort cho Hàm AutoFilter
Các hàm này là đối số nằm trong hàm FilterSort hoặc AutoFilter

aftSortNotHeader()
Không
Đặt vùng sort không có tiêu đề

aftSortDescending()

Đặt sắp xếp chiều ngược lại

aftSortMatchCase()

Đặt điều kiện sắp xếp phân biệt Hoa Thường

aftSortMethod(Method)

Không hiển thị nút lọc trên trang tính

aftSortDataOption(DataOption)

aftSortOn(SortOn)

aftSortOrientation(Orientation)

Ví dụ gõ hàm: =AutoFilter(A1:C1000,A1:A1000,aftCriteria1(">=1") ,FilterSort(aftSortDescending(),aftSortMatchCase())

2. AdvFilter: là hàm bổ trợ cho phương thức AdvancedFilter trong Application Excel
****************(Sớm cập nhật)****************

***Lưu ý:
1. Phiên bản đầu tiên nên có các lỗi khi sử dụng, nên cần cập nhật và sửa lỗi, các bạn nên tham khảo và theo dõi chủ đề để cập nhật.
2. Chưa viết mã cho AdvFilter
3. Sẽ sớm cập nhật sắp xếp có cấp độ

Sao chép mã bên dưới vào một Module mới, và sử dụng hàm:

Option Explicit
Option Compare Text
Public Const ProjectName = "UDFFilterXL"
Public Const ProjectFileName = "AutoFilterXL"
Public Const projectVersion = "1.0"

'                    _,
' ___   _   _  _ ___(_)
'/ __| /  | | | _ | |
'__ /  | \ | _  |
'|___/_/ _|_|_|___/_|
'

Public Enum AutoFilterSettings
  afsMainFXAutoFilter = 1
  afsMainFXAdvancedFilter
  afsFilterSort
  afsField
  afsCriteria1
  afsOperator
  afsCriteria2
  afsDisibleDropDown
  afsSubField
  afsCells
  ' Sort -------------------------
  afsSortDescending
  afsSortOn
  afsSortDataOption
  afsSortNotHeader
  afsSortMatchCase
  afsSortOrientation
  afsSortMethod
End Enum

Private Type TypeArguments
  timer As Single
  Action As Long
  direction As Long
  Target As Variant
  address As String
  caller As Range
  formula As String

Field As Variant
  Criteria1 As Variant
  Operator As XlAutoFilterOperator
  Criteria2 As Variant
  DisibleDropDown As Boolean
  SubField As Variant
  Title As String
  actionFT As XlFilterAction
  CriteriaRange As Range
  CopyToRange As Range
  Unique As Boolean
  resultArray As Variant
  Cells As Range
  CurrentCells As Range
  XLNew As Boolean
  OnUndo As Boolean
  FilterSort As Boolean
  SortDescending As Boolean ' xlAscending
  SortOn As XlSortOn ' xlSortOnValues
  SortDataOption As XlSortDataOption ' = xlSortNormal
  SortHeader As Boolean
  SortMatchCase As Boolean
  SortOrientation As Long
  SortMethod As XlSortMethod
End Type

#If VBA7 Then
  Public Declare PtrSafe Function SetTimer Lib "USER32" (ByVal Hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long
  Public Declare PtrSafe Function KillTimer Lib "USER32" (ByVal Hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
  Public Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
  Public Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
#End If

Private Works() As TypeArguments

Function afoBottom10Items(): AddArgumentsFilter afsOperator, xlBottom10Items: End Function
Function afoBottom10Percent(): AddArgumentsFilter afsOperator, xlBottom10Percent: End Function
Function afoFilterAutomaticFontColor(): AddArgumentsFilter afsOperator, xlFilterAutomaticFontColor: End Function
Function afoFilterCellColor(): AddArgumentsFilter afsOperator, xlFilterCellColor: End Function
Function afoFilterDynamic(): AddArgumentsFilter afsOperator, xlFilterDynamic: End Function
Function afoFilterFontColor(): AddArgumentsFilter afsOperator, xlFilterFontColor: End Function
Function afoFilterIcon(): AddArgumentsFilter afsOperator, xlFilterIcon: End Function
Function afoFilterNoFill(): AddArgumentsFilter afsOperator, xlFilterNoFill: End Function
Function afoFilterNoicon(): AddArgumentsFilter afsOperator, xlFilterNoIcon: End Function
Function afoFilterValues(): AddArgumentsFilter afsOperator, xlFilterValues: End Function
Function afoAnd(): AddArgumentsFilter afsOperator, xlAnd: End Function
Function afoOr(): AddArgumentsFilter afsOperator, xlOr: End Function
Function afoTop10Items(): AddArgumentsFilter afsOperator, xlTop10Items: End Function
Function afoTop10Percent(): AddArgumentsFilter afsOperator, xlTop10Percent: End Function

'=AutoFilter(B4:AF24,C4:C24,aftField(1),aftCriteria1(">="&C1),aftCriteria2("<="&C2),afoAnd())
Function AdvFilter(ByVal CurrentCells As Range, ByVal FilterCells As Range, ParamArray arguments()) As Variant
  AdvFilter = AddArgumentsFilter(afsMainFXAdvancedFilter, CurrentCells, FilterCells)
End Function

Function AutoFilter(ByVal CurrentCells As Range, ByVal FilterCells As Range, ParamArray arguments()) As Variant
  AutoFilter = AddArgumentsFilter(afsMainFXAutoFilter, CurrentCells, FilterCells)
End Function

Function FilterSort(ParamArray arguments()) As Variant
  Call AddArgumentsFilter(afsFilterSort, arguments)
End Function

Function aftSortDescending()
  AddArgumentsFilter afsSortDescending, True
End Function
Function aftSortOn(Optional SortOn As XlSortOn = xlSortOnValues)
  AddArgumentsFilter afsSortDataOption, SortOn
End Function
Function aftSortDataOption(Optional DataOption As XlSortDataOption = xlSortNormal)
  AddArgumentsFilter afsSortDataOption, DataOption
End Function
Function aftSortNotHeader()
  AddArgumentsFilter afsSortNotHeader, False
End Function
Function aftSortMatchCase()
  AddArgumentsFilter afsSortMatchCase, True
End Function
Function aftSortOrientation(Optional Orientation As Long = xlTopToBottom)
  AddArgumentsFilter afsSortOrientation, Orientation
End Function
Function aftSortMethod(Optional Method As XlSortMethod = xlPinYin)
  AddArgumentsFilter afsSortMethod, Method
End Function

Function aftField(Field As Variant) As Variant
  AddArgumentsFilter afsField, Field
End Function

Function aftCriteria1(Criteria As Variant) As Variant
  AddArgumentsFilter afsCriteria1, Criteria
End Function
Function aftOperator(Optional Operator As XlAutoFilterOperator = xlAnd) As XlAutoFilterOperator
  AddArgumentsFilter afsOperator, Operator
End Function
Function aftCriteria2(Criteria As Variant)
  AddArgumentsFilter afsCriteria2, Criteria
End Function
Function aftDisibleDropDown() As String
  AddArgumentsFilter afsDisibleDropDown, False
End Function
Function aftSubField(SubField As Variant) As Variant
  AddArgumentsFilter afsSubField, SubField
End Function

Private Function AddArgumentsFilter(direction%, ParamArray arguments())
  On Error Resume Next
  Dim k%, i%, r As Object, s$, f$, w As TypeArguments, n As Boolean
  Set r = Application.ThisCell: If r Is Nothing Then Exit Function

If r.Worksheet.ProtectContents = True Then AddArgumentsFilter = "[SheetProtected]": Exit Function

XLAppVersion n
  If n Then f = r.Formula2 Else f = r.formula

If Not f Like "*AutoFilter(*" Then Exit Function

s = r.address(0, 0, , 1)

k = UBound(Works):
  If k > 0 Then
    For i = 1 To k
      With Works(i)
        If s = .address And f = .formula Then
          Select Case .Action
          Case 1: k = i: GoTo s
          Case 2: Exit Function
          Case 3: Exit Function
            If direction = afsMainFXAutoFilter Then
              If n Then .direction = -1
              .Action = 4
              AddArgumentsFilter = .resultArray: Call SetTimer(Application.Hwnd, 1113, 0, AddressOf S_AutoFilter_callback)
            End If
            Exit Function
          End Select
          Exit For
        End If
      End With
    Next
  End If
  k = k + 1
  ReDim Preserve Works(1 To k)
  With Works(k): .XLNew = n: .Action = 1: .OnUndo = False: .direction = 0: Set .caller = r: .address = s: .formula = f: .Operator = 1: .Field = 1
    .SortDescending = False
    .SortHeader = True
    .SortMatchCase = False
    .SortOn = xlSortOnValues
    .SortDataOption = True
    .FilterSort = False
    .SortMethod = xlPinYin
    .SortOrientation = xlTopToBottom
  End With
s:
  With Works(k)
    Select Case direction
    Case afsFilterSort: .FilterSort = True
    Case afsMainFXAdvancedFilter: .direction = direction
    Case afsMainFXAutoFilter: .direction = direction
       .OnUndo = Application.CommandBars("Standard").Controls("&Undo").List(1) = "Filter"
      .timer = timer: Set .CurrentCells = arguments(0): Set .Cells = arguments(1): Call FilterSetTimer
    Case afsField: .Field = arguments(0)
    Case afsCriteria1: .Criteria1 = arguments(0)
    Case afsOperator: .Operator = arguments(0)
    Case afsCriteria2: .Criteria2 = arguments(0)
    Case afsDisibleDropDown: .DisibleDropDown = True
    Case afsSubField: .SubField = arguments(0)
    Case afsSortDescending: .SortDescending = True
    Case afsSortNotHeader: .SortHeader = False
    Case afsSortMatchCase: .SortMatchCase = True
    Case afsSortDataOption: .SortDataOption = arguments(0)
    Case afsSortOn: .SortOn = arguments(0)
    Case afsSortDescending: .SortDescending = True
    Case afsSortOrientation: .SortOrientation = arguments(0)
    End Select
  End With
End Function

''///////////////////////////////////////////////////////
Private Sub FilterSetTimer()
  Call SetTimer(Application.Hwnd, 1111, 0, AddressOf S_AutoFilter_callback)
End Sub

#If VBA7 And Win64 Then
Private Sub S_AutoFilter_callback(ByVal Hwnd^, ByVal uMsg&, ByVal nIDEvent&, ByVal dwTimer&)
#Else
Private Sub S_AutoFilter_callback(ByVal Hwnd&, ByVal uMsg&, ByVal nIDEvent&, ByVal dwTimer&)
#End If
  On Error Resume Next
  Call KillTimer(Hwnd, nIDEvent)
  Select Case nIDEvent
  Case 1111: S_AutoFilter_working
  Case 1113:
    Dim k%, i%, j%
    k = UBound(Works):
    For i = 1 To k
      If Works(i).Action = 4 Then j = j + 1
    Next
    If j = k Then Erase Works
  End Select
End Sub
'learn.microsoft.com/en-us/office/vba/api/excel.range.sort?source=recommendations
Private Sub S_AutoFilter_working()
  'If ThisWorkbook.BookJustSaved Then Erase Works: Exit Sub
  Dim ub As Integer, a As Object, b As TypeArguments, i&, k&, lr&, r1&, su As Boolean, ac As Boolean, ee As Boolean, v As Variant, rg As Range, cell
  ub = UBound(Works)
  Dim s$, o, sh
  For i = 1 To ub
    b = Works(i)
    Select Case b.Action
    Case 1
      If b.caller.formula = b.formula Then
        If a Is Nothing Then
          Set a = Application
          su = a.ScreenUpdating: If su Then a.ScreenUpdating = False
          ee = a.EnableEvents: If ee Then a.EnableEvents = False
          'ac = a.Calculation = xlCalculationAutomatic: If ac Then a.Calculation = xlCalculationManual
        End If
        Set rg = b.Cells: Set sh = rg.parent
        If Not sh.AutoFilter Is Nothing Then sh.AutoFilter.ShowAllData
        If IsEmpty(b.Criteria2) Then
          If IsEmpty(b.SubField) Then
            b.Cells.AutoFilter Field:=b.Field, Criteria1:=b.Criteria1, Operator:=b.Operator, VisibleDropDown:=Not b.DisibleDropDown
          Else
            b.Cells.AutoFilter Field:=b.Field, Criteria1:=b.Criteria1, Operator:=b.Operator, Criteria2:=b.Criteria2, VisibleDropDown:=Not b.DisibleDropDown, SubField:=b.SubField
          End If
        Else
          If IsEmpty(b.SubField) Then
            b.Cells.AutoFilter Field:=b.Field, Criteria1:=b.Criteria1, Operator:=b.Operator, Criteria2:=b.Criteria2, VisibleDropDown:=Not b.DisibleDropDown
          Else
            b.Cells.AutoFilter Field:=b.Field, Criteria1:=b.Criteria1, Operator:=b.Operator, Criteria2:=b.Criteria2, VisibleDropDown:=Not b.DisibleDropDown, SubField:=b.SubField
          End If
        End If
        If b.FilterSort Then
          With sh
              .AutoFilter.Sort.SortFields.Clear
              .AutoFilter.Sort.SortFields.Add2 _
                Key:=b.CurrentCells, SortOn:=b.SortOn, Order:=1 - b.SortDescending, _
                DataOption:=b.SortDataOption
            With .AutoFilter.Sort: .Header = b.SortHeader: .MatchCase = False: .Orientation = b.SortOrientation: .SortMethod = b.SortMethod: .Apply: End With
          End With
        End If
        lr = b.CurrentCells.rows.count
        Set cell = b.CurrentCells(1, 1).MergeArea
        r1 = cell.rows.count
        If Not b.FilterSort Or Not b.SortHeader Then
          Set cell = b.CurrentCells
        Else
          Set cell = b.CurrentCells.Offset(r1, 0).Resize(lr - r1)
        End If
        Works(i).resultArray = cell.Value2
        If b.XLNew Then
          b.caller.Formula2 = b.formula
        Else
          cell.Copy b.caller: b.caller.formula = b.formula
        End If
        Works(i).Action = 3
      End If
    End Select
    k = k + 1
n:
  Next
  Erase Works
  If Not a Is Nothing Then
    If su And a.ScreenUpdating <> su Then a.ScreenUpdating = su
    If ee And a.EnableEvents <> ee Then a.EnableEvents = ee
    'If ac And xlCalculationAutomatic <> a.Calculation Then a.Calculation = ac
    Set a = Nothing
  End If
  On Error GoTo 0
End Sub

Private Function XLAppVersion(Optional newVersion As Boolean, Optional implicitIntersectionOperator$, Optional SpillOperator$) As Long
  Static n&, v&, i1$, i2$
  If n <> 0 Then XLAppVersion = v: newVersion = n = 1: implicitIntersectionOperator = i1: SpillOperator = i2: Exit Function
  Dim registryObject As Object
  Dim rootDirectory$
  Dim keyPath$
  Dim arrEntryNames As Variant
  Dim arrValueTypes As Variant
  Dim x&
  Select Case val(Application.Version)
  Case Is = 16
    'Check for existence of Licensing key
    i1 = "@"
    keyPath = "SoftwareMicrosoftOffice" & CStr(Application.Version) & "CommonLicensingLicensingNext"
    rootDirectory = "."
    Set registryObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & rootDirectory & "rootdefault:StdRegProv")
    registryObject.EnumValues &H80000001, keyPath, arrEntryNames, arrValueTypes
    On Error GoTo ErrorExit
    For x = 0 To UBound(arrEntryNames)
      If InStr(arrEntryNames(x), "365") > 0 Then n = 1: v = 365: Exit For
      If InStr(arrEntryNames(x), "2019") > 0 Then
        If Application.Build >= 14332 Then
          'ProductCode: {90160000-000F-0000-1000-0000000FF1CE}
          'CalculationVersion:  191029
          n = 1: i2 = "#": v = 2021
        Else
          n = -1: v = 2019
        End If
        Exit For
      End If
      If InStr(arrEntryNames(x), "2016") > 0 Then v = 2016: n = -1: Exit For
    Next x
  Case Is = 15: n = -1: v = 2013
  Case Is = 14: n = -1: v = 2010 'ProductCode: {91140000-0011-0000-1000-0000000FF1CE} 'CalculationVersion:  145621
  Case Is = 12: n = -1: v = 2007
  Case Else: n = -1: v = 0
  End Select
  newVersion = n = 1: XLAppVersion = v: implicitIntersectionOperator = i1: SpillOperator = i2
Exit Function
ErrorExit:
  'Version 16, but no licensing key. Must be Office 2016
  v = 2016: n = -1: XLAppVersion = v: newVersion = n = 1
End Function

www.giaiphapexcel.com/diendan/threads/t%E1%BA%ADn-d%E1%BB%A5ng-b%E1%BB%99-l%E1%BB%8Dc-autofilter-v%C3%A0-advancedfilter-v%E1%BB%9Bi-h%C3%A0m-udf-nhanh-ch%C3%B3ng.164047/

Khóa học Power PI – Ứng dung trong Nhân sự
Khóa học SprinGO phù hợp

Khóa học Power PI – Ứng dung trong Nhân sự

TỔNG QUAN KHÓA HỌC: POWER BI CHO NGÀNH NHÂN SỰ Khóa học Power BI cho Nhân sự được thiết kế dành riêng cho các...

Xem khóa học
★★★★★ 5 ★ 1 👤 3 ▥ 0
Quảng cáo

Bạn nên đọc

Bình luận

Quảng cáo

Cũ vẫn chất

Xem thêm