Filtering multiple pivot tables based on drop down selections using VBA

后端 未结 1 575
终归单人心
终归单人心 2021-01-28 07:26

I\'m hoping someone can help. I have a dashboard created by someone else where there are numerous tables across sheets all operating from drop down date selections (From - To) o

相关标签:
1条回答
  • 2021-01-28 07:56

    Here's a couple of suggestions.

    1. What version of Excel do you have? You may be able to simply sidestep the issue if using Excel 2010 or later, because you can simply set up a Slicer on the date field, and then connect that Slicer to any PivotTables that you want to sync. In later versions you can do the same using a specialised slicer called a Timeline. I wrote a related post on this some time back at the following link that might be of interest: http://dailydoseofexcel.com/archives/2014/08/16/sync-pivots-from-dropdown/

    2. According to IronyAaron in the comments at this thread:

      When VBA recognizes the dates in the pivot cache, it reads the US version after parsing although the item is read as a locally formatted string. This therefore causes VBA to fail when recognizing Date variables.

    That might be your issue. I recently experienced some similar issues and got around it by converting the date I wanted to filter the Pivot on to a DateSerial (to get around US vs Non-US date 'incompatibilities') and then cast that DateSerial as a Long, with the following line of code:

    CLng(DateSerial(Year(vItem), Month(vItem), Day(vItem)))

    Your code may need something like this. If you amend your question to include the exact code that isn't working then I'll take a look.

    1. Check out this recent SO question I answered: It might be easily amended to do what you want. Filtering pivot table with vba

    ---Edit---

    The most efficient way to filter pivots programmatically on a date range is to leverage the inbuilt Date Between functionality, i.e. this thing:

    The only problem is that this functionality isn't available to PageFields (i.e. fields dragged to the Filters pane) as per the following screenshot:

    So if you want to use the following code, you'll have to drag your Month fields into the PivotTable as a RowField, like so:

    Assuming that's not going to present any issues, then you can use the following code:

    Private Sub Worksheet_Change(ByVal Target As Range)
    
    Dim pt As PivotTable
    Dim vItem As Variant
    Dim rFrom As Range
    Dim rTo As Range
    
    With Application
        .ScreenUpdating = False
        .EnableEvents = False
        .Calculation = xlCalculationManual
    End With
    
    Set rFrom = Range("dvFrom")
    Set rTo = Range("dvTo")
    
    If Not Intersect(Target, rFrom) Is Nothing Or Not Intersect(Target, rTo) Is Nothing Then
        If rFrom < rTo Then
            For Each vItem In Array("PivotTable1", "PivotTable2") 'Change PivotTable names as appropriate
                Set pt = Sheet1.PivotTables(vItem) 'Change Sheet as appropriate
                With pt.PivotFields("Month")
                    .ClearAllFilters
                    .PivotFilters.Add2 _
                        Type:=xlDateBetween, _
                        Value1:=CLng(DateSerial(Year(rFrom), Month(rFrom), Day(rFrom))), _
                        Value2:=CLng(DateSerial(Year(rTo), Month(rTo), Day(rTo)))
                        'I use "CLng(DateSerial" because otherwise VBA may get confused
                        ' if the user's Excel i set to a non US dateformat.
                End With
            Next vItem
        End If
    End If
    
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
    End With
    
    End Sub
    

    Note that I've assigned the names dvFrom and dvTo to your data validation dropdowns, and then referenced those names in the code. You'll have to do the same in your master sheet.

    If you don't want to change your PivotTable layout, then a workaround is to add a TimeLine on the month field, and programmatically change that via the dropdowns. It will then update the PivotTable. Here's how that looks:

    Note that the Month field doesn't look like it has a filter applied, but it does...as evidenced by the totals that display in the PivotTable.

    Here's the modified code for the Timeline-driven version:

    Private Sub Worksheet_Change(ByVal Target As Range)
    
    Dim vItem As Variant
    Dim rFrom As Range
    Dim rTo As Range
    Dim lFrom As Long
    Dim lTo As Long
    Dim dte As Date
    
    With Application
        .ScreenUpdating = False
        .EnableEvents = False
        .Calculation = xlCalculationManual
    End With
    
    Set rFrom = Range("dvFrom")
    Set rTo = Range("dvTo")
    
    If Not Intersect(Target, rFrom) Is Nothing Or Not Intersect(Target, rTo) Is Nothing Then
        lFrom = CLng(DateSerial(Year(rFrom), Month(rFrom), Day(rFrom)))
        lTo = CLng(DateSerial(Year(rTo), Month(rTo), Day(rTo)))
        If lFrom < lTo Then
            For Each vItem In Array("NativeTimeline_Month", "NativeTimeline_Month1") 'Adjust timeline names as neccessary
                ActiveWorkbook.SlicerCaches(vItem).TimelineState. _
                    SetFilterDateRange lFrom, lTo
            Next vItem
        End If
    End If
    
    
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = xlCalculationAutomatic
    End With
    
    
    End Sub
    

    And that leaves us with your original approach - iterating through the PivotItems. It turns out that this is not just horribly inefficient, but also requires you temporarily to change your number format of the Month field from a MMM-YY format to a DD-MM-YY format or similar, because otherwise VBA might misinterpret the Year as a day, and then use the current year as the year. So if your PivotItem is OCT-15 then VBA interprets that as 15 October 2016 (the current year as I type this) instead of 1 October 2015. Nasty.

    So I'd advise steering clear of iteration, and either change your PivotTable format and use my first approach, or add a TimeLine and use my second approach.

    0 讨论(0)
提交回复
热议问题