【问题标题】:Select all Pivot Items that match list of items in another Excel sheet选择与另一个 Excel 工作表中的项目列表匹配的所有数据透视项目
【发布时间】:2018-07-20 12:17:16
【问题描述】:

我有一张 Excel 表格,其中包含人员及其相关部门的列表。在另一个工作表上的数据透视表中,我想过滤我的结果,以便显示给定部门中任何人“分配给”的所有项目。

到目前为止,我的代码可以将人员列表过滤到所需部门,并创建一个包含所有这些人员姓名的数组。然后,我尝试过滤包含这些名称列表的 PivotItems,使其可见,而所有其他名称都隐藏,但是当我尝试运行宏时,它只是在不断思考。有没有更简单的方法来做到这一点?

ActiveSheet.Range("$A$1:$E$175").AutoFilter Field:=4, Criteria1:= _
        "DEPARTMENT NAME"

'Selects first visible row of filtered data set & _
 create array that contains all filtered names  
ActiveSheet.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Cells(3, 2).Select
employeerange = "C" & ActiveCell.Row & ":C" & ActiveSheet.Rows.Count
Dim employeearray As Variant
employeearray = Range(employeerange).Value

'Cycle through all possible items for the given Pivot Field and compare to _ 
 each of the names in the employee array.  Set items that match to visible _ 
 and all others to hidden.

Dim PI As PivotItem
Dim element As Variant
    With ActiveSheet.PivotTables("PivotTable2").PivotFields("PIVOT FIELD")
        For Each PI In .PivotItems
            For Each element In employeearray
            If PI Like "*" & CStr(element) & "*" Then
                PI.Visible = True
                Else
                PI.Visible = False
            End If
            Next element
        Next PI
    End With

【问题讨论】:

    标签: excel vba foreach pivot-table


    【解决方案1】:

    在对 PivotItem 进行迭代时,您需要避免一些瓶颈和陷阱。有关更多信息,请参阅我在 http://dailydoseofexcel.com/archives/2013/11/14/filtering-pivots-based-on-external-ranges/ 的帖子。

    除其他事项外,您还希望在执行迭代时将数据透视表的 ManualUpdate 属性设置为 TRUE,然后在完成后将其设置为 FALSE。否则,每次您更改数据透视表的可见性时,Excel 都会尝试更新数据透视表。而且您还希望确保至少有一个项目始终可见。我使用这样的东西:

    Option Explicit
    
    Sub FilterPivot()
    Dim pt As PivotTable
    Dim pf As PivotField
    Dim pi As PivotItem
    Dim i As Long
    Dim vItem As Variant
    Dim vCountries As Variant
    
    Set pt = ActiveSheet.PivotTables("PivotTable1")
    Set pf = pt.PivotFields("CountryName")
    
    vCountries = Array("FRANCE", "BELGIUM", "LUXEMBOURG")
    
    pt.ManualUpdate = True 'Stops PivotTable from refreshing after each PivotItem is changed
    
    With pf
    
        'At least one item must remain visible in the PivotTable at all times, so make the first
        'item visible, and at the end of the routine, check if it actually  *should* be visible        
        .PivotItems(1).Visible = True
    
        'Hide any other items that aren't already hidden.
        'Note that it is far quicker to check the status than to change it.
        ' So only hide each item if it isn't already hidden
        For i = 2 To .PivotItems.Count
            If .PivotItems(i).Visible Then .PivotItems(i).Visible = False
        Next i
    
        'Make the PivotItems of interest visible
        On Error Resume Next 'In case one of the items isn't found
        For Each vItem In vCountries
            .PivotItems(vItem).Visible = True
        Next vItem
        On Error GoTo 0
    
        'Hide the first PivotItem, unless it is one of the countries of interest
        On Error Resume Next
        If InStr(UCase(Join(vCountries, "|")), UCase(.PivotItems(1))) = 0 Then .PivotItems(1).Visible = False
        If Err.Number <> 0 Then
            .ClearAllFilters
            MsgBox Title:="No Items Found", Prompt:="None of the desired items was found in the Pivot, so I have cleared the filter"
        End If
        On Error GoTo 0
    
    End With
    
    pt.ManualUpdate = False
    
    End Sub
    

    【讨论】:

    • 感谢 Jeffrey,我能够让这段代码正常工作!我在描述中遗漏的一件关键事情是该数组将包含一个名称列表,但数据透视表中的项目可能与该列表不完全匹配(即,之后可能会添加一个中间名首字母)。有没有办法调整此代码以在数据透视表中查找类似项目,例如我在原始代码中使用的“PI Like”?
    • 嗨,凯瑟琳。很高兴这篇文章有所帮助。请将答案标记为有用,如果它解决了问题,请接受它。关于您的问题,这基本上就是所谓的模糊匹配,并且在计算上非常昂贵并且编码起来非常棘手。几年来我一直在开发一个商业应用程序,并且几乎准备好发布它,但我担心它是一个付费产品。
    【解决方案2】:

    您是否检查过构建数组的代码的第一部分?我看不到你的数据,但我不确定这是否会如你所愿。

    要构建您的数组,请使用以下内容:

    ActiveSheet.Range("$A$1:$E$175").AutoFilter Field:=4, Criteria1:= "DEPARTMENT NAME"
    Dim employeearray As Variant
    employeearray = ActiveSheet.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Columns("C").Value
    

    至于宏的第二部分..

    您正在过度测试匹配,如果您让它运行,它将隐藏除最后一个匹配之外的所有内容。

    改为使用以下代码,它会循环所有 .PivotItems,但使用单个测试来检查项目是否在数组中。

    Dim PI As PivotItem
        With ActiveSheet.PivotTables("PivotTable2").PivotFields("PIVOT FIELD")
            For Each PI In .PivotItems
                PI.Visible = (UBound(Filter(employeearray, PI.Name)) > -1)
            Next PI
        End With
    

    【讨论】:

    • 感谢 CLR 的建议!当我尝试这样做时,我得到了一个不匹配错误,即使代码显示 PI.Visible 被设置为 true。可能是因为该项目最初设置为 true 吗?
    • 我在您的推荐中的 for 循环之前添加了 Jeffrey 的代码,用于将所有枢轴项的可见性设置为 false。当我这样做时代码运行,但它使所有项目都不可见,即使我知道应该有匹配项。数组中的值可能与数据透视表中的值略有不同(即它们可能缺少中间的首字母)。我的理解是过滤器函数将返回数组中的项目,即使它不是完全匹配,就像我的情况一样。还有什么我可能做错的吗?
    • VBA 中的Filter 函数将生成一个包含匹配项的数组(在我的示例中),其中employeearray 中的任何项目在其文本中都包含PI.Name。因此,如果employeearray 项目之一包含“JOHN H SMITH”而PI.Name 是“JOHN SMITH”,则它将不匹配。事实上,只有非常复杂的方法可以尝试这种匹配——比如模糊搜索。如果 PI.Name 是“JOHN”或“SMITH”,那么它会匹配,因为它们可以在“JOHN SMITH”中找到。
    • 另一种选择是创建一个转换数组/表,例如允许将“JOHN H SMITH”转换为“JOHN*SMITH”,以便“JOHN H SMITH”或“JOHN SMITH” " 会匹配它。
    猜你喜欢
    • 1970-01-01
    • 2021-12-03
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 2015-07-21
    • 2022-11-07
    相关资源
    最近更新 更多