Excel 2013 VBA Pivot Table Select Only Top 5 Items With Ties - excel

I am trying to find a way to use Excel 2013 VBA to only select the Top 5 items in a pivot table. I have tried the following lines of code in an attempt to show only the Top 5 items:
Dim c
dim i as long
Worksheets("sheet1").PivotTables(1).PivotFields ("field1")
ActiveSheet.PivotTables(1).PivotFields("field1").CurrentPage = "(All)"
With ActiveSheet.PivotTables(1).PivotFields("field1")
c = 5
For i = .PivotItems.Count To 1 Step -1
If (c > 0) Then
.PivotItems(i).Visible = True
Else
.PivotItems(i).Visible = False
End If
c = c - 1
Next
End With
This is the code that the macro recorder gives me and does not work:
ActiveSheet.PivotTables("PivotTable5").PivotFilters. _
.PivotFields("field1") Add2 Type:=xlTopCount, _ DataField:=ActiveSheet.PivotTables("PivotTable5"). _
PivotFields("fied1"), Value1:=5
The code below works fine if there are no value ties for any of the values that are not in the Top 5 list. With our data set we are always going to ties in our Top 5 list.
With Workbooks(cFileName).Worksheets("sheet1")
.PivotTables(1).PivotFields("Field1").PivotFilters.Add2
xlTopCount, .PivotTables(1).PivotFields("Field1"), 5
End With
EDIT:
The pivot table list will show some items as being checked, but no data is associated with those values. The charts which are based on these pivot tables are blank and the following code selects only the bottom 5 values in the field as it was intended to do in it's original post.
With workbook.Worksheets("sheet1").PivotTables("PivotTable2").PivotFields
("Count of Description")
For Each WS In ActiveWorkbook.Worksheets
For Each pvt In WS.PivotTables
c = 5
For i = .PivotItems.Count To 1 Step -1
If (c > 0) Then
.PivotItems(i).Visible = True
Else
.PivotItems(i).Visible = False
End If
c = c - 1
Next
Next
Next
End With

I finally figured this one out. The best way to do it just in case anyone else is wondering, is to record a macro while you:
Select the cell in which you want to start seeing data. In my case it was "B10". This will be different for everyone else depending on where your pivot table data is.
Press the SHIFT + END + DOWN ARROW Keys to go down to the bottom of the used range.
Select all the rows to hide.
Right Click on the values to hide.
Select "Filter" from the list.
Click on "Hide selected items".
Below is the code that I will refer to in the future.
Application.Goto reference:=Workbooks("File").Sheets("Sheet1").Range("B10")
If IsEmpty(Range("B11").value) = False Then
Range("B10").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Delete
Else
End If

Related

How to Expand and Collapse Cells without Pivoting or Using Group Data Options

How can I add expand and collapse button in excel without Pivot Table or Group Data, same as the attached picture?
expand and collapse button
A few years ago I wrote something like this for a customer. The code below demonstrates the macro attached to a button that expands/collapses a pre-defined Named-Range ("pRngPurchaseOrders").
This range has "guard rows" which are just empty rows at the beginning and end of the range, and thus if there are <= 2 rows in the range, we assume that it is empty and call an update routine to get data from a database to fill-in the range (if you don't need this, just ignore that branch and treat the range as collapsed).
' Expand or collapse the PurchaseOrder display region
Sub ExpandPurchaseOrders()
Debug.Print Format(Now, "HH:mm:SS "), "ExpandPurchaseOrders begin"
' get the PurchaseOrders range
Dim nPurchaseOrders As Name, rPurchaseOrders As Range, lenPurchaseOrders As Long
Set nPurchaseOrders = ws.Names("pRngPurchaseOrders")
Set rPurchaseOrders = nPurchaseOrders.RefersToRange
lenPurchaseOrders = rPurchaseOrders.Rows.Count
' if len=2 then assume we are expanding/expanded and updatePurchaseOrders
' if len > 2 and row(2) is invisible then we are collapsed, so expand and then updatePurchaseOrders
' if len > 2 and row(2) is visible then collapse
If lenPurchaseOrders = 2 Then
' no rows, so we are expanding, but effectively already expanded
PurchaseOrdersUpdate
ElseIf lenPurchaseOrders > 2 Then
Dim i As Long
If rPurchaseOrders.Rows(2).Hidden = True Then
'EXPAND: unhide all of the PurchaseOrder rows
For i = 2 To lenPurchaseOrders - 1
'first and last rows are hidden and used as anchors, so skip them
rPurchaseOrders.Rows(i).Hidden = False
Next i
' and update
PurchaseOrdersUpdate
Else
'COLLAPSE: hide all of the PurchaseOrder rows
For i = 2 To lenPurchaseOrders - 1
'first and last rows are hidden and used as anchors, so skip them
rPurchaseOrders.Rows(i).Hidden = True
Next i
End If
End If
Debug.Print Format(Now, "HH:mm:SS "), "ExpandPurchaseOrders Done"
End Sub
To use this I simply created a button on the sheet with a "+" in the text next to the named range, and assigned this macro to it.

Speeding up VBA pivot table filtering

I'm trying to figure out why my Pivot table filtering is so very slow, using VBA. The table itself doesn't have too many rows - about 5000 in total. But this slice of code takes about 30 seconds to make the update, and it makes Excel appear to be frozen. I'm using an Array to pass in two values to the filter that I am using. In this case, there are two "People" that I want to select in this filter. What am I missing?
'
Set PT = ActiveSheet.PivotTables("PivotTable1")
Dim i As Integer
i = 0
For Each PTItm In PT.PivotFields("Person").PivotItems
i = i + 1
If Not IsError(Application.Match(PTItm.Caption, myArray, 0)) Then
PTItm.Visible = True
Else
PTItm.Visible = False
End If
Next PTItm
As additional information, I also tried to start by setting Visible = False on all of the items (except for the last Item, since you have to leave at least one Item visible), and then just setting the Visible = True for the Items that I want. But the problem is that just getting through all of the Items and setting to False (snip below) takes the same ~ 30 seconds.
With PT
For jj = 1 To .PivotFields("Person").PivotItems.Count - 1
.PivotFields("Person").PivotItems(jj).Visible = False
Next
End With

Change Pivot Table Columns Filters with changing source data

I have built a macro that connects to SAP, do its thing, gets the response and writes it down on the spreadsheet. The issue is, before the script could do it, I need to have the data by cluster.
For understanding, I have a list of customers with their codes and I have built a master key for each of them, because before I input it to SAP, I need to filter the customers by master key codes that are equal so SAP will accept it. But on the source file I'll have multiples master key codes.
I made a pivot table and put the master key on the columns, so I can see customers code by master key.
With that in hand I filter by master key and I have the specific customer codes for it, and now I can send it to SAP. And repeat for all master keys on the file.
This information will change every time from the sales department, so the master keys will change everytime too.
What I need to do is get all the master keys from the file (done that) and, the place I'm stuck, use it to hide and show one at time inside a loop.
For example (MK stands for Master Key):
Customer MK1 MK2 MK3 MK4
X 1
Y 1
Z 1
A 1
So I filter MK1, get customer code for it, run SAP thing, get back to the pivot, filter next existing code, get the customers code, run SAP and do all over again.
If Range("A2") <> "" Then
Range("A1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(-1, 1).Select
Range(Selection, Selection.End(xlUp)).FillDown
FILTRO2 = ActiveCell
Range("A1").Select
Do While ActiveCell <> ""
FILTRO = ActiveCell
Sheets("Dinâmica").Activate
ActiveWorkbook.RefreshAll
With ActiveSheet.PivotTables("Tabela dinâmica2").PivotFields("Chave")
.PivotItems(Split(FILTRO2.Value, ",")).Visible = False
.PivotItems(FILTRO).Visible = True
End With
As seen on above code, I'm on a dead end. Isn't working at all.
You can switch each single "masterkey" visible by Pivotitem.Visible.
Please be aware, that always at least 1 pivotitem has to remain visible.
The resulting visible "customers" can be read from the PivotField.DataRange, which represents all visible pivotitems of that pivotfield. You can address that range cell by cell or assign its value to an array.
Private Sub FilterMasterkeys()
Dim pt As PivotTable
Dim pfCustomer As PivotField
Dim pfMasterkey As PivotField
Dim i As Long
Dim c As Range ' a cell
Set pt = ActiveWorkbook.Sheets("Dinâmica").PivotTables("Tabela dinâmica2")
pt.RefreshTable
Set pfCustomer = pt.RowFields(1)
Set pfMasterkey = pt.ColumnFields("Chave")
' hide all masterkeys except first
pfMasterkey.PivotItems(1).Visible = True
For i = 2 To pfMasterkey.PivotItems.Count
pfMasterkey.PivotItems(i).Visible = False
Next i
' set each masterkey visible and get corresponig customers
For i = 1 To pfMasterkey.PivotItems.Count - 1
pfMasterkey.PivotItems(i).Visible = True
Debug.Print "Masterkey " & pfMasterkey.PivotItems(i).Caption & " is used by ",
For Each c In pfCustomer.DataRange.Cells
Debug.Print c.Value,
Next c
Debug.Print
pfMasterkey.PivotItems(i + 1).Visible = True
pfMasterkey.PivotItems(i).Visible = False
Next i
' get the last one also
Debug.Print "Masterkey " & pfMasterkey.PivotItems(i).Caption & "is used by ",
For Each c In pfCustomer.DataRange.Cells
Debug.Print c.Value,
Next c
Debug.Print
End Sub
If you need all corresponding customers as array, use this after you have switched the next masterkey visible:
Dim arrCustomers() As Variant
arrCustomers = pfCustomer.DataRange.Value

Use VBA to select an Excel slicer value

I am trying to go through a slicer in VBA, this is my code:
ActiveWorkbook.SlicerCaches("Slicer_Customer_Name1").ClearManualFilter 'Opens the slicer we want to focus on
With ActiveWorkbook.SlicerCaches("Slicer_Customer_Name1")
For countCustomer = 1 To 100
Sheet4.Cells(countCustomer, 3) = Sheet3.Cells(5, 1)
prevCustomer = countCustomer - 1
If countCustomer > 1 Then
.SlicerItems(countCustomer).Selected = True
.SlicerItems(prevCustomer).Selected = False
End If
Next countCustomer
End With
What I want to do is go through the slicer and print out the value in cell A5 for each different filtered value. I need it to complete code for a project where this is just the foundation.

Select multiple items in a slicer

I have working code which selects single items from a slicer, however it doesn't work for multiple items.
The selection is set up by reading which cells in a range are in bold, and populating an array of strings, STP(46), populating up until STP(k). This works fine.
Then the code is supposed to deselect all items in the slicer which aren't in STP, and select those which are. This works for one selection but not for multiple selections - it erroneously selects all items up until the last item to be selected.
With ActiveWorkbook.SlicerCaches("Slicer_STP_Name")
For i = 1 To .SlicerItems.Count
For j = 1 To k
If .SlicerItems(i).Selected And .SlicerItems(i).Caption <> STP(j) Then .SlicerItems(i).Selected = False
Next j
Next i
For i = 1 To .SlicerItems.Count
For j = 1 To k
If .SlicerItems(i).Caption = STP(j) Then .SlicerItems(i).Selected = True: Exit For
Next j
Next i
End with
So instead of selecting, say, the 2nd and 4th item in the slicer, it selects the 1st, 2nd, 3rd, 4th, and deselects the rest.
I need to use a looped technique like this because I need to be able to use this code with multiple slicers with different cache names but the same list of items.
I've looked everywhere, and the code above is even from a solution from another question on here. Any help greatly appreciated!
You can use a dictionary to make the process a little more smooth
With ActiveWorkbook.SlicerCaches("Slicer_test_id")
Dim i
For i = 1 To .SlicerItems.Count
If .SlicerItems(i).Selected And Not stp.Exists(.SlicerItems(i).Caption) Then
.SlicerItems(i).Selected = False
End If
Next i
For i = 1 To .SlicerItems.Count
If stp.Exists(.SlicerItems(i).Caption) Then
.SlicerItems(i).Selected = True
End If
Next i
End With
I'm not totally clear on why you need the first loop. I'm reading "Then the code is supposed to deselect all items in the slicer which aren't in STP, and select those which are." as "select only those otems in STP and deselect all others" which this reduced code will do:
With ActiveWorkbook.SlicerCaches("Slicer_test_id")
Dim i
For i = 1 To .SlicerItems.Count
.SlicerItems(i).Selected = stp.Exists(.SlicerItems(i).Caption)
Next i
End With
populating the Dictionary is super easy
Dim stp As New Dictionary
stp.Add "73148", "73148"
stp.Add "73150", "73150"
stp.Add "73159", "73159"
You need to reference the Microsoft Scripting Runtime
note that if you don't see Microsoft Scripting Runtime in the list you can Browse to C:\Windows\SysWOW64\scrrun.dll

Resources