VBA Code to Control Multiple Pivot Table Slicers - vba

I'm trying to set-up some VBA code that will allow me to control multiple pivot tables (and data sources) with 1 slicer.
In the past, I have only needed to implement VBA code that controls 1 additional slicer, but now I am trying to set-it up to control 2 slicers and am running into issues.
Here is my code that I used in the past for controlling 1 slicer:
As a module:
Public PrevCat As String
In ThisWorkbook:
Private Sub Workbook_Open()
PrevCat = Sheet27.Range("O5").Value
End Sub
Primary code:
Option Explicit
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
NewCat = Sheet27.Range("O5").Value
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 2")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
Application.ScreenUpdating = True
End Sub
Like I said, this code works perfectly for controlling 1 additional slicer. However, I need the code to control 2 slicers. All i did was add an additional If statement, but it doesn't seem to work:
Option Explicit
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
NewCat = Sheet27.Range("O5").Value
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 2")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 3")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
Application.ScreenUpdating = True
End Sub
Any ideas on how i can get this to work?

Related

How to speed up this VBA code with slicers?

I have a spreadsheet with seven tables (tbl_1, tbl_2 ...tbl_7) each controlled by its own slicer. Each slicer has six buttons (10, 20, 30, 40, 50, 60) referring to Team Codes. I use the code below to select one team on every slicer, then create a PDF for each team / slicer setting. As of now, the code takes anywhere from 5-7min to run. Any help is much appreciated.
Sub SlicerTeam()
Dim wb As Workbook
Dim sc As SlicerCache
Dim si As SlicerItem
On Error GoTo errHandler
Application.ScreenUpdating = False
Application.EnableEvents = False
Set wb = ThisWorkbook
For x = 1 To 6
For i = 1 To 7
Set sc = wb.SlicerCaches("tbl_" & i)
sc.ClearAllFilters
For Each si In sc.VisibleSlicerItems
Set si = sc.SlicerItems(si.Name)
If Not si Is Nothing Then
If si.Name = x * 10 Then
si.Selected = True
Else
si.Selected = False
End If
Else
si.Selected = False
End If
Next si
Next i
Call PDFCreate
Next x
exitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
errHandler:
MsgBox ("Error in updating slicer filters.")
Resume exitHandler
End Sub
Assuming that these slicers are slicing pivot tables, try the below code. It may help speed things up, depending on how big your PivotTables are.
Sub SlicerTeam()
Dim wb As Workbook
Dim sc As SlicerCache
Dim si As SlicerItem
dim pt as PivotTable
On Error GoTo errHandler
Application.ScreenUpdating = False
Application.EnableEvents = False
Set wb = ThisWorkbook
For Each pt in wb.PivotTables
pt.ManualUpdate = True
Next
For x = 1 To 6
For i = 1 To 7
Set sc = wb.SlicerCaches("tbl_" & i)
sc.ClearAllFilters
For Each si In sc.VisibleSlicerItems
Set si = sc.SlicerItems(si.Name)
If Not si Is Nothing Then
If si.Name = x * 10 Then
si.Selected = True
Else
si.Selected = False
End If
Else
si.Selected = False
End If
Next si
Next i
For Each pt in wb.PivotTables
pt.ManualUpdate = True
Next
Call PDFCreate
Next x
exitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
errHandler:
MsgBox ("Error in updating slicer filters.")
Resume exitHandler
End Sub
After several trials.. found this is the best option.
Disable calculations:
Application.ScreenUpdating = False
With Application
.EnableEvents = False
.Calculation = xlCalculationManual
End With
type code to Remove slicer conections.... example:
ActiveWorkbook.SlicerCaches("Slicer_Area").PivotTables.RemovePivotTable ( _
ActiveSheet.PivotTables("PivotDatosGraficoAbsoluto"))
Set slicer value to true, and others to false... example:
Set MySlicerCache = ActiveWorkbook.SlicerCaches("Slicer_Area")
For i = 1 To MySlicerCache.SlicerItems.Count
With MySlicerCache.SlicerItems(i)
If .Name = "Comercial GJ" Then
.Selected = True
'Range("E1").Value = .Name
Else:
.Selected = False
End If
End With
Next i
Do the Slicer conections.. example:
ActiveWorkbook.SlicerCaches("Slicer_Area").PivotTables.AddPivotTable ( _
ActiveSheet.PivotTables("PivotDatosGraficoAbsoluto"))
Enable Events:
With Application
.EnableEvents = True
.Calculation = xlCalculationAutomatic
End With
This will save aprox 40% of waiting time

Code not working for Pivot Data Set having Rows>65536

My purpose is to create a Pivot Table and further a Pivot Chart out of the Dump data (A1:AE170000) I have. I've attached my code below, which works perfectly fine if I reduce my data to around 60-65k rows, but not otherwise.
It throws Runtime error 13 : Type Mismatch at the line I am setting up my Pivot Cache (PTCache).
Private Sub OptionButton3_Click()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ThisWorkbook.Sheets("Data").Activate
Dim PTCache As PivotCache
Dim PT As PivotTable
'Setting range as my entire data set
Dim PTRange As Range
Set PTRange = Range("A1", Range("A1").End(xlToRight).End(xlDown))
'Adding a new worksheet for Pivot Table and Chart
Dim ws As Worksheet
Set ws = Sheets.Add
ws.Name = "All"
PTRange.Select
ThisWorkbook.Sheets("All").Activate
'Runtime error 13:Type Mismatch at this line while setting PTCache
Set PTCache = ActiveWorkbook.PivotCaches.Create(xlDatabase, PTRange)
Set PT = ActiveSheet.PivotTables.Add(PTCache, Range("A1"), "All")
With PT
.PivotFields("Name").Orientation = xlPageField
.PivotFields("Rate").Orientation = xlDataField
.PivotFields("Date").Orientation = xlRowField
End With
PT.PivotSelect ("")
Charts.Add
ActiveChart.Location where:=xlLocationAsObject, Name:=PT.Parent.Name
ActiveChart.ChartType = xlLine
ActiveChart.Parent.Top = Range("I7").Top
ActiveChart.Parent.Left = Range("I7").Left
Range("A2").Select
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
From PivotCaches.Create Method (Excel) (my emphasis):
<blah><blah> ... When passing as a range, it is recommended to either use a string to specify the workbook, worksheet, and cell range, or set up a named range and pass the name as a string. Passing a Range object may cause "type mismatch" errors unexpectedly.
Just set up a string var to the external address of the Data worksheet's Range.CurrentRegion property radiating out from A1 and use that.
Option Explicit
Private Sub OptionButton3_Click()
'Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim PT As PivotTable, PTCache As PivotCache
Dim PTRange As Range, ws As Worksheet, strRNG As String
strRNG = ThisWorkbook.Worksheets("Data").Cells(1, 1).CurrentRegion.Address(external:=True)
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = "All"
Set PTCache = .Parent.PivotCaches.Create(xlDatabase, strRNG)
Set PT = .PivotTables.Add(PTCache, .Range("A1"), "All")
With PT
.PivotFields("Name").Orientation = xlPageField
.PivotFields("Rate").Orientation = xlDataField
.PivotFields("Date").Orientation = xlRowField
End With
PT.PivotSelect ("")
End With
'all the chart stuff here
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Multiple Private Subs Worksheet_Change in same worhsheet

I have the following sub in a worksheet, but I need another 3 of the same in the same worksheet for different cells/pivots. How can I do that?
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'This line stops the worksheet updating on every change, it only updates when cell
'B1 or B2 is touched
If Intersect(Target, Range("B1:B2")) Is Nothing Then Exit Sub
'Set the Variables to be used
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
'Here you amend to suit your data
Set pt = Worksheets("Daily Overall").PivotTables("DailyOverallSignups")
Set Field = pt.PivotFields("Reg Year")
NewCat = Worksheets("Daily Overall").Range("B1").Value
'This updates and refreshes the PIVOT table
With pt
Field.ClearAllFilters
Field.CurrentPage = NewCat
pt.RefreshTable
End With
End Sub
I assume that by "the same" you mean that they all need to be in worksheet_selectionchange? Since your code currently exits if it isn't b1:b2, change your code to not exit at that point by adding other ranges. You should also have error handling and enableevents in there.
Private Sub Worksheet_SelectionChange(ByVal target As Range)
On Error GoTo Bummer
'This line stops the worksheet updating on every change, it only updates when cell
'B1 or B2 is touched
If Not Intersect(target, Range("B1:B2")) Is Nothing Then 'if not nothing
Application.EnableEvents = False
'Set the Variables to be used
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
'Here you amend to suit your data
Set pt = Worksheets("Daily Overall").PivotTables("DailyOverallSignups")
Set Field = pt.PivotFields("Reg Year")
NewCat = Worksheets("Daily Overall").Range("B1").Value
'This updates and refreshes the PIVOT table
With pt
Field.ClearAllFilters
Field.CurrentPage = NewCat
pt.RefreshTable
End With
ElseIf Not Intersect(target, Range("c1:c2")) Is Nothing Then
Application.EnableEvents = False
MsgBox ("Foo")
ElseIf Not Intersect(target, Range("d1:d2")) Is Nothing Then
Application.EnableEvents = False
MsgBox ("Bar")
ElseIf Not Intersect(target, Range("e1:e2")) Is Nothing Then
Application.EnableEvents = False
MsgBox ("Hello World")
Else
Exit Sub
End If
MovingOn:
Application.EnableEvents = True
Exit Sub
Bummer:
MsgBox Err.Description
Resume MovingOn
End Sub

Use VBA to change filters on all pivot tables

I have an Excel workbook with several hundred pivot tables. All of the pivot tables are using data from an SSAS cube. The tables are all basically structured the same way, but they have different "location" filters. What I want to do is have code that will change a "date" filter for all of the tables so that I do not need to manually update each of the tables. (No, slicers will not work for me). I'm very much new to using VBA, so I'm a bit at a loss. I found this code, which I thought might work, but all it does for me is clear the filters on the other tables...possibly because I'm pulling from an external source? Any help would be greatly appreciated.
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
On Error Resume Next
Dim wsMain As Worksheet
Dim ws As Worksheet
Dim ptMain As PivotTable
Dim pt As PivotTable
Dim pfMain As PivotField
Dim pf As PivotField
Dim pi As PivotItem
Dim bMI As Boolean
On Error Resume Next
Set wsMain = ActiveSheet
Set ptMain = Target
Application.EnableEvents = False
Application.ScreenUpdating = False
For Each pfMain In ptMain.PageFields
bMI = pfMain.EnableMultiplePageItems
For Each ws In ThisWorkbook.Worksheets
For Each pt In ws.PivotTables
If ws.Name & "_" & pt <> wsMain.Name & "_" & ptMain Then
pt.ManualUpdate = True
Set pf = pt.PivotFields(pfMain.Name)
bMI = pfMain.EnableMultiplePageItems
With pf
.ClearAllFilters
Select Case bMI
Case False
.CurrentPage = pfMain.CurrentPage.Value
Case True
.CurrentPage = "(All)"
For Each pi In pfMain.PivotItems
.PivotItems(pi.Name).Visible = pi.Visible
Next pi
.EnableMultiplePageItems = bMI
End Select
End With
bMI = False
Set pf = Nothing
pt.ManualUpdate = False
End If
Next pt
Next ws
Next pfMain
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Kindly try the following code.
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
On Error Resume Next
Dim wsMain As Worksheet
Dim ws As Worksheet
Dim ptMain As PivotTable
Dim pt As PivotTable
Dim pfMain As PivotField`enter code here`
Dim pf As PivotField
Dim pi As PivotItem
Dim pvfilter as string
On Error Resume Next
Set wsMain = ActiveSheet
Set ptMain = Target
Application.EnableEvents = False
Application.ScreenUpdating = False
pvfilter = InputBox("Enter the pivot filter string")
For Each pfMain In ptMain.PageFields
For Each ws In ThisWorkbook.Worksheets
For Each pt In ws.PivotTables
If ws.Name & "_" & pt <> wsMain.Name & "_" & ptMain Then
pt.ManualUpdate = True
Set pf = pt.PivotFields(pfMain.Name)
With pf
.ClearAllFilters
.CurrentPage = pvfilter
End With
Set pf = Nothing
pt.ManualUpdate = False
End If
Next pt
Next ws
Next pfMain
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
I would suggest you update this code as subroutine and run this macro whenever you need to apply a filter to pivot tables instead of directly using the code in pivot update event.
Sub Test()
On Error Resume Next
Dim wsMain As Worksheet
Dim ws As Worksheet
Dim ptMain As PivotTable
Dim pt As PivotTable
Dim pfMain As PivotField
Dim pf As PivotField
Dim pi As PivotItem
Dim pvfilter As String
On Error Resume Next
Set wsMain = ActiveSheet
Set ptMain = Target
Application.EnableEvents = False
Application.ScreenUpdating = False
pvfilter = InputBox("Enter the pivot filter string")
For Each pfMain In ptMain.PageFields
For Each ws In ThisWorkbook.Worksheets
For Each pt In ws.PivotTables
If ws.Name & "_" & pt <> wsMain.Name & "_" & ptMain Then
pt.ManualUpdate = True
Set pf = pt.PivotFields(pfMain.Name)
With pf
.ClearAllFilters
.CurrentPage = pvfilter
End With
Set pf = Nothing
pt.ManualUpdate = False
End If
Next pt
Next ws
Next pfMain
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub

Data validation and combo box in a cell - Workbook_SheetChange event not working

I have adapted the following code from Contextures website which adds combo box functionality into cells containing data validation. Though comboboxes display well where they should, I am still facing two issues.
First, I would need that after chosing value in "D4" cell, which combines data validation and combo box, the same value was displayed on other sheets in "D4" cell in the workbook. Unfortunately, after comboboxes code was added, the Workbook_SheetChange code stopped working. I assume it is because it cannot find Target in data validation/combobox cell now.
The second issue is that the Worksheet_SelectionChange code below causes screen flickering even though Application.ScreenUpdating is applied. Is there any way to get rid of it?
I would be greatful for any solutions.
EDIT:
At last I managed to find solution to first issue myself. I ommited Workbook_SheetChange event entirely and replaced with ComboShtHeader_KeyDown and ComboShtHeader_LostFocus events, both placed in the workbook sheets. These macros ensure that value of a cell changes on all sheets either on pressing Tab, Enter or click outside "D4" cell. I am placing both codes below for the case that someone faces similar issue.
The other issue with screen flickering in Worksheet_SelectionChange code persists though. Solutions are still welcome.:-)
Private Sub ComboShtHeader_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'change "D4" cell value on all sheets on pressing TAB or ENTER
Dim ws1 As Worksheet, ws As Worksheet
Set ws1 = ActiveSheet
Select Case KeyCode
Case 9 'Tab
ActiveCell.Offset(0, 1).Activate
For Each ws In Worksheets
If ws.Name <> ws1.Name Then
ws.Range(ActiveCell.Offset(0, -3).Address).Value = ActiveCell.Offset(0, -3).Value
End If
Next ws
Case 13 'Enter
ActiveCell.Offset(1, 0).Activate
For Each ws In Worksheets
If ws.Name <> ws1.Name Then
ws.Range(ActiveCell.Offset(-1, 0).Address).Value = ActiveCell.Offset(-1, 0).Value
End If
Next ws
Case Else
'do nothing
End Select
End Sub
Private Sub ComboShtHeader_LostFocus()
'change "D4" cell value on all sheets on click outside "D4" cell
Dim ws1 As Worksheet, ws As Worksheet
Set ws1 = ActiveSheet
For Each ws In Worksheets
If ws.Name <> ws1.Name Then
ws.Range("D4").Value = ws1.Range("D4").Value
End If
Next ws
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim ws As Worksheet, ws2 As Worksheet
Dim ComHead As OLEObject, ComBody As OLEObject
Dim Str As String
Application.ScreenUpdating = False
On Error GoTo ErrHandler
Set ws = ActiveSheet
Set ws2 = Worksheets("lists")
Set ComHead = ws.OLEObjects("ComboShtHeader")
Set ComBody = ws.OLEObjects("ComboShtBody")
On Error Resume Next
If ComHead.Visible = True Then
With ComHead
.Top = 34.5
.Left = 120
.Width = 20
.Height = 15
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
.Value = ""
End With
End If
On Error Resume Next
If ComBody.Visible = True Then
With ComBody
.Top = 34.5
.Left = 146.75
.Width = 20
.Height = 15
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
.Value = ""
End With
End If
On Error GoTo ErrHandler
'If the cell contains a data validation list
If Target.Validation.Type = 3 Then
If Target.Address = ws.Range("D4:F4").Address Then
If Target.Count > 3 Then GoTo ExitHandler
Application.EnableEvents = False
'Get the data validation formula
Str = Target.Validation.Formula1
Str = Right(Str, Len(Str) - 1)
With ComHead
'Show the combobox with the validation list
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 15
.Height = Target.Height
.ListFillRange = ws2.Range(Str).Address(external:=True)
.LinkedCell = Target.Address
End With
ComHead.Activate
'Open the dropdown list automatically
Me.ComboShtHeader.DropDown
Else
If Target.Count > 1 Then GoTo ExitHandler
Application.EnableEvents = False
'Get the data validation formula
Str = Target.Validation.Formula1
Str = Right(Str, Len(Str) - 1)
With ComBody
'Show the combobox with the validation list
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 15
.Height = Target.Height
.ListFillRange = ws2.Range(Str).Address(external:=True)
.LinkedCell = Target.Address
End With
ComBody.Activate
'Open the dropdown list automatically
Me.ComboShtBody.DropDown
End If
End If
ExitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
ErrHandler:
Resume ExitHandler
End Sub
The second code, placed in ThisWorkbook module and currently not working:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim wb1 As Workbook
Dim ws1 As Worksheet, ws As Worksheet
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set wb1 = ThisWorkbook
Set ws1 = Sh
On Error GoTo LetsContinue
'This should change "D4" value on all sheets, but does not work after combobox feature was added to the sheets.
If Not Intersect(Target, ws1.Range("D4")) Is Nothing Then
MsgBox Target.Address 'returns nothing
For Each ws In wb1.Worksheets
If Target.Value <> ws.Range(Target.Address).Value Then
ws.Range(Target.Address).Value = Target.Value
End If
Next ws
Else
GoTo LetsContinue
End If
LetsContinue:
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
Actually, the second issue that regarded screen flickering solved itself when I moved from Excel 2007 to 2013 version. It seems like some kind of bug in older version.