使用具有动态范围的自动过滤器

Posted

技术标签:

【中文标题】使用具有动态范围的自动过滤器【英文标题】:Using Autofilter with a dynamic range 【发布时间】:2021-11-27 16:09:10 【问题描述】:

仍在学习绳索,所以请耐心等待!我有一个每月数据转储,它将被复制到工作簿中,它始终采用相同的格式。我正在尝试编写一个宏,该宏使用工作簿中另一个工作表中的名称列表来过滤预设列中的数据。理想情况下,我希望能够从列表中添加或删除名称。过滤后,我希望它复制所有可见的单元格并将它们粘贴到新工作表中。

我开始使用自动过滤器,然后使用计数数组,但我收到一个错误并且它没有过滤。因为过滤器应用于工作表,但它似乎无法查找实际名称,并且只返回空白。 它似乎确实在我的动态列表中计算了正确的名称数量......所以我会接受。

所以示例数据: 工作表:名称

工作表:书籍

理想情况下,代码从“姓名”中的“人员”列中获取姓名列表,查看“姓名”列“书籍”,找到每个匹配项,然后将整行复制并转储到新工作表中。

这是我写东西的最佳尝试。

Sub FilterName()
Dim i As Long
Dim lastrow As Long
Dim arrSummary() As Variant

With ThisWorkbook.Sheets("Names")
  lastrow = .Cells(Rows.Count, "B").End(xlUp).Row
  ReDim arrSummary(1 To lastrow)

  For i = 1 To lastrow
  arrSummary(i) = .Cells(i, 1)
  Next

End With
For i = LBound(arrSummary) To UBound(arrSummary)
      With ThisWorkbook.Sheets("Books")
      .Range("F:F").AutoFilter Field:=1, Criteria1:=arrSummary(i), Operator:=xlFilterValues
      
    .ThisWorkbook.Sheets("Books").Range("A1:AA100000").SpecialCells(xlCellTypeVisible).Copy
    'Getting error 438 here
    .ThisWorkbook.Sheets("Loans").Paste
      End With
Next i

End Sub

我确实考虑过高级过滤器,但即使在 VBA 之外也无法使其工作,然后不想做查找路线,因为觉得它很笨重...不过愿意探索这些选项。

干杯:)

【问题讨论】:

Range("F:F")之前需要一个句号 谢谢,已更新。我的视力不是我想象的那样! 您必须删除 AutoFilter-Row 下方“ThisWorkbook”之前的句点 【参考方案1】:

如果您有 Excel 365,您可以在没有 VBA 的情况下实现您的目标,但使用新的 FILTER 功能。

在我的示例中,我创建了两个表(插入 > 表),分别命名为 tblPeople 和 tblBooks。

这样公式就很容易阅读了:

关于你的代码:当你有很多数据时,这个过程会很慢。

一般来说,将数据读入数组时会获得更好的性能(就像你已经对人民表所做的那样),在数组中进行过滤,然后将数组写回工作表(你会发现很多SO上的示例。

顺便说一句:您可以像这样将范围读取到数组中: arrSummary = rg.value 其中rg 是您要读取的范围。

【讨论】:

干杯,遗憾的是没有 excel 365,它是给另一个团队成员的。他们理想地希望这个魔法过滤器只需点击一个按钮,不需要额外的格式化/工作。因此,我渴望使用 VBA 来解决问题。如果是我的话,我会用这个,所以谢谢!【参考方案2】:

过滤器名称

它将标准工作表 (cws) 的B (cCol) 列中的值写入一个基于1 的二维一列数组(cData)。然后它将遍历数组中的值,并通过每个数组的值过滤 源工作表 (sws) 的第 6 列 (scCol) 并复制源范围的 (@987654327 @) 包含与目标工作表 (dws) 的第一个可用行匹配的单元格的行,从A (dfCol) 列开始。
Option Explicit

Sub FilterNames()
    
    ' Criteria
    Const cName As String = "Names"
    Const cCol As String = "B"
    Const cfRow As Long = 2
    ' Source
    Const sName As String = "Books"
    Const sCols As String = "A:AA"
    Const scCol As Long = 6 ' also used for AutoFilter's Field parameter
    Const sfRow As Long = 1
    ' Destination
    Const dName As String = "Loans"
    Const dfCol As String = "A"
    Const dfRow As Long = 2
    ' Workbook
    Dim wb As Workbook: Set wb = ThisWorkbook
    
    ' Criteria
    Dim cws As Worksheet: Set cws = wb.Worksheets(cName)
    Dim clRow As Long: clRow = cws.Cells(cws.Rows.Count, cCol).End(xlUp).Row
    If clRow < cfRow Then Exit Sub
    Dim crCount As Long: crCount = clRow - cfRow + 1
    Dim crg As Range: Set crg = cws.Cells(cfRow, cCol).Resize(crCount)
    Dim cData As Variant
    If crCount = 1 Then
        ReDim cData(1 To 1, 1 To 1): cData(1, 1) = crg.Value
    Else
        cData = crg.Value
    End If
    
    ' Source
    Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
    Dim srg As Range: Set srg = sws.UsedRange.Columns(sCols)
    Dim sdrg As Range: Set sdrg = srg.Resize(srg.Rows.Count - 1).Offset(1)
    Dim sdcrg As Range: Set sdcrg = sdrg.Columns(scCol)
    
    ' Destination
    Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
    Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dfCol).End(xlUp).Row
    Dim dCell As Range
    If dlRow < dfRow Then
        Set dCell = dws.Cells(dfRow, dfCol)
    Else
        Set dCell = dws.Cells(dlRow, dfCol).Offset(1)
    End If
    
    Application.ScreenUpdating = False
    
    Dim drCount As Long
    Dim r As Long
    
    For r = 1 To UBound(cData, 1)
        sws.AutoFilterMode = False
        srg.AutoFilter scCol, CStr(cData(r, 1)), xlFilterValues
        drCount = Application.Subtotal(103, sdcrg)
        Debug.Print drCount, cData(r, 1)
        If drCount > 0 Then
            sdrg.SpecialCells(xlCellTypeVisible).Copy
            dCell.PasteSpecial xlPasteValues
            Set dCell = dCell.Offset(drCount)
        End If
    Next r

    Application.CutCopyMode = False
    sws.AutoFilterMode = False
    
    If dws Is ActiveSheet Then
        dws.Range("A1").Activate
    Else
        Dim ash As Worksheet: Set ash = ActiveSheet
        dws.Activate
        dws.Range("A1").Activate
        ash.Activate
    End If
    
    'wb.Save
    
    Application.ScreenUpdating = True
    
    MsgBox "Data transferred.", vbInformation, "Filter Names"
    
End Sub

【讨论】:

以上是关于使用具有动态范围的自动过滤器的主要内容,如果未能解决你的问题,请参考以下文章

使用 Google 表格中的单个公式从范围创建动态排序和过滤列表

excel vba自动过滤范围并删除co​​l D中所有带0的行

如何从过滤器中自动选择范围而无需手动输入?

在具有德国区域设置的计算机上使用 VBA 自动过滤器过滤日期问题

基于具有唯一值的数组创建多个动态选择过滤器以过滤 Vue.js 中的另一个数组

具有动态和静态刚体的 PhysX 碰撞过滤器