selecting a field from pivot table using vba macro - excel

I have created a pivot table using vba. I need help with the understanding of below-mentioned points.
1: I want to select(copy) values with certain filters (eg: Underlying price
for Instrument Type = OPTCUR, Symbol = GBPUSD). Basically a VBA alternative for formula
GETPIVOTDATA("Underlying_price",$C$4,"Instrument Type","OPTCUR","Symbol","GBPUSD")
2: I want to set "show detail=True" without knowing cell details but the criteria as mentioned above.
3: when we set "show detail=True" a new sheet opens. i want to asign this sheet to a variable of type worksheet.
below is the SS of my pivot table. and TableName:="My_Pivot"

You get the relevant cell with PivotTable.GetPivotData
The new worksheet with details of this cell is shown by Range.ShowDetail = True.
Directly after that, the new ActiveSheet is the wanted one.
Here is a function to get the wanted worksheet with the details for a specified data field:
Private Function GetDetailSheet(pt As PivotTable, Val1 As String, Val2 As String) As Worksheet
Dim myCell As Range
With pt
Set myCell = .GetPivotData(.DataFields(1).Name, _
.RowFields(1).Name, Val1, _
.RowFields(2).Name, Val2)
End With
myCell.ShowDetail = True
Set GetDetailSheet = ActiveSheet
End Function
It can be used like this:
Private Sub Test()
Dim ws as Worksheet
Set ws = GetDetailSheet(ActiveSheet.PivotTables("My_Pivot"), "OPTCUR", "GBPUSD")
ws.Name = "Details OPTCUR GBPUSD"
End Sub

If you don't want to use the (hideos) GETPIVOTDATA there's a solution for you!
It's called CUBEVALUE. It's a bit difficult to master but once it's done you reports & Pivot Table get to a whole new level.
See here: https://www.excelcampus.com/cubevalue-formulas/
Yes, it's a long article, but it's definitely worth the effort, as it would enable you to point to a specific data point, not to a specific cell.
Once mastered, adding a VBA code to a "changed" cell event and changing the visibility status of a certain sheet is just a matter of minutes.

Related

Combine new dynamic array features of excel with VBA

I tried to work a bit more with dynamic arrays in excel in combination with vba. My problem is that I cant return a table-column with vba. Here a minimal example of what I want to do:
I have two Tables TabFeb and TabMar (see image below). Each of them has a column costs which I want to sum up individually. The results shall be put into a new Table. This can be easily done in excel with =SUM(TabFeb[Costs]) and =SUM(TabMar[Costs]), respectively. My idea is now to write a VBA function which takes a string as input, in this example it will be the month, and returns the table acording to the input. After that it will be summed up and the result is given in a cell.
I tried the following:
Function Selectmon(mon As String) As Range
If mon = "Feb" Then
Set Selectmon = Worksheets("Sheet1").ListObjects("TabFeb").ListColumns("Costs").DataBodyRange
ElseIf mon = "Mar" Then
Set Selectmon = Worksheets("Sheet1").ListObjects("TabMar").ListColumns("Costs").DataBodyRange
End If
End Function
The problem of this idea is that this function just copy the table data. Hence, if I would change the input table data the sum would not change. One has to recalculate every cell by hand. Somehow I need VBA to return TabFeb[Costs] for the input "Feb". Does anyone have an idea how this can be done?
Example
It's really just a one-liner (unless you want to do some in-function error checking)
Function Selectmon(mon As String) As Range
Set Selectmon = Range("Tab" & mon & "[Costs]")
End Function
As implied by #ceci, this formula will not update with changes in the table. Depending on other particulars of your worksheet, you can have it update either by
embedding it in a worksheet change event code;
or by adding the line Application.Volatile to the function itself.
The latter method will force a recalculation when anything changes on the worksheet that might cause a recalculation.
The first method can limit the recalculation only when there has been a change in the data, but has other limitations.
One of the limitations of the Worksheet Change method is that it will only work on the relevant worksheet.
If you use the Workbook sheet change method, you won't have that limitation.
In either event you can limit your code to run only when the table has changed.
Here is one generalized method:
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim LOS As ListObjects
Dim LO As ListObject
Set LOS = Sh.ListObjects
For Each LO In LOS
'could select relevant tables here
'Could also select relevant worksheets, if you like
'for example
Select Case LO.Name
Case "TabFeb", "TabMar", "TabApr"
If Not Intersect(LO.DataBodyRange, Target) Is Nothing Then
Application.EnableEvents = False
Application.Calculate
End If
End Select
Next LO
Application.EnableEvents = True
End Sub
And there is other code you could use to find the relevant formula and just update that formula -- probably not worth the effort.

Hiding empty columns in a table in excel using VBA

I have an excel sheet with a table and its quite large so I also have a slicer to break it up in viewable pieces. My problem is that then selecting a specific unit in the slicer sometimes there will be columns in the table that's empty. I would very much like to make a button to hide them (and then have another button to unhide so I can select other units in the slicer and view new data and so on...)
My problem is that most VBA code online hides all the columns outside the table. Im not in any way fluent in VBA. I have unsuccessfully tried to modifying code I found only. From what I can see online, most codes define an area/range within a worksheet and then loops over that range and hides all empty columns. But then I try to redefine the range as the ListObjects("Table1")the code fails.
So far i have managed to make code that unhides all columns outside the table and I have tried to make a small piece of code that hides the
Sub ShowHidden()
Rows.Hidden = False
Columns.Hidden = False
End Sub
Sub HideEmptyColumns()
ActiveSheet.ListObjects("Table1").Columns.Hidden = True
End Sub
The latter fails
Is it possible to make code that hides empty columns in a table in excel and if so, how does the code look
Kind regards
Need to use the properties of the ListObject object (Excel), in this case use the DataBodyRange to set the range to loop after.
You'll also need to use Range.SpecialCells method (Excel)
Dim lo As ListObject
Set lo = ThisWorkbook.Worksheets("DATA").ListObjects("lo.Data") 'change as required
For Each rCol In lo.DataBodyRange.Columns
'… Here goes the validation of the cells within the column (i.e. rCol)
If … Then rCol.EntireColumn.Hidden = True
Next
To unhide the columns use:
Dim lo As ListObject
Set lo = ThisWorkbook.Worksheets("DATA").ListObjects("lo.Data") 'change as required
lo.DataBodyRange.EntireColumn.Hidden = False

VBA Pivot filter on multiple cell ranges applied to multiple tables

While this topic is widely discussed I've been unable to find a proper solution to this issue.
As a data analyst, I would like to apply filters across multiple pivot table based on values in multiple cell ranges.
I have looked for answers and tried to apply these solutions:
https://www.mrexcel.com/forum/excel-questions/950078-filtering-pivot-table-based-cell-value.html
and this:
https://www.youtube.com/watch?v=xCJgCRuVU6c&t=201s
Specifically this code:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
'This line stops the worksheet updating on every change, it only updates when cell
'A1 to A9 is touched
If Intersect(Target, Worksheets(1).Range("A1:A9")) 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(1).PivotTables("PivotTable1")
Set Field = pt.PivotFields("Sales Region")
NewCat = Worksheets(1).Range("A1:A9").Value
'This updates and refreshes the PIVOT table
With pt
Field.ClearAllFilters
Field.CurrentPage = NewCat
pt.RefreshTable
End With
End Sub
however, they do not apply 100% as firstly it doesn't update anything at all (no reponse) and secondly it only applies the filter to the first column even if it would work.
Please see attached photo of how I'd like the model to look.
Above is of course not entirely true as the filtering options would remove many of the values in the tables.
The pivot tables have the IDs "PivotTable1" & "PivotTable2".
Worksheet is called "Sheet1".
I would like to be able to change these values and also the filter options (e.g. to include a Date value filter.
Please let me know if anything is unclear.
Also, if there are any other options that doesn't include VBA, these will also be well received.

Structured reference changes to absolute when copied across sheets

I have a monster of a workbook that I'm trying to make more manageable for those that use it after me. I have a ton of code that is ran when buttons are pressed to make it more user friendly to those that know little to nothing of Excel. So here is where I need help.
I have several sheets with similar tables. My first sheet contains a Master List of customer information and pressing a button, copies this information to each other sheet and sorts it to categorize these customers on their respective sheets. This allows me to enter new information only on the first sheet and have it auto-populate the sheets correctly to minimize human error.
To cut down on a lot of the errors, I utilized structured referencing in tables. I didn't originally have it this way, but I've been trying to improve this workbook over time.
Anyway, so I have a column "Charge Type" in each table, and the total column references it as
[#[Charge Type]]
which is great, considering customers will be added and removed pretty regularly and this cuts down on errors.
However, when this formula gets copied to one of the other sheets, it's converted over to
All_List[#[Charge Type]]
which adds the name of the table on sheet1, which is "All_List". Now I want it to refer to the column "Charge Type" specifically in the new table on the new sheet, and I cannot for the life of me figure out how.
This solution uses a variable to hold the ListObject "Field" formula then loops trough all other ListObjects in the same workbook with the same "Field" and applies the formula to that "Field".
ListObjects before
Sub ListObjects_Formula_Copy()
Dim wsh As Worksheet
Dim lob As ListObject
Dim rTrg As Range
Dim sFld As String
Dim sFmlR1C1 As String
Rem Get Formula from Primary ListObject
sFld = "Price" 'Change as required
Set lob = ThisWorkbook.Sheets("Sht(0)").ListObjects(1) 'Change as required
sFmlR1C1 = lob.ListColumns(sFld).DataBodyRange.Cells(1).FormulaR1C1
Rem Apply Formula to Other ListObjects
For Each wsh In ThisWorkbook.Worksheets
If wsh.Name <> "Sht(0)" Then
For Each lob In wsh.ListObjects
Rem Validate Field
Set rTrg = Nothing
On Error Resume Next
Set rTrg = lob.ListColumns(sFld).DataBodyRange
On Error GoTo 0
Rem Applies Formula
If Not (rTrg Is Nothing) Then rTrg.FormulaR1C1 = sFmlR1C1
Next: End If: Next
End Sub
ListObjects after

Sort a ListObject by Columns

I am working with ListObject objects in VBA. In particular I am creating a table dynamically (variable number of rows and columns, and variable column headers). I have the need to sort the table's columns in ascending alphabetical order.
For instance if I have the table:
I want it to be sorted like so,
Is there any way to do this? I have tried to use the Range.Sort method but it seems that this is not allowed if the range is part of a ListObject.
I also tried to record a macro to find code, but found that when I right clicked the table to sort it, the selected range left the header out and I was not able to select the "Sort left to right" option...
Any ideas?
This seems to work. It takes the name of a table (e.g. "Table1"), converts it to a range, sorts it, then reconverts it to a table with the same name:
Sub SortByCol(tableName As String)
Dim sh As Worksheet
Dim myTable As ListObject
Dim myStyle As TableStyle
Dim myRange As Range
Set sh = ActiveSheet
Set myTable = sh.ListObjects(tableName)
Set myStyle = myTable.TableStyle
Set myRange = myTable.Range
myTable.Unlist
On Error Resume Next
myRange.Sort key1:=myRange.Rows(1), Orientation:=xlSortRows
If Err.Number > 0 Then Debug.Print "Range couldn't be sorted"
On Error GoTo 0
sh.ListObjects.Add(xlSrcRange, myRange, , xlYes).Name = tableName
sh.ListObjects(tableName).TableStyle = myStyle
End Sub
On edit: I added a bit of error handling around the sort method call. Experiments showed that my original code didn't preserve the style (if the table didn't have the default style then the result was a weird blend of the default style and the original table style). I added coded to save and then restore the original table style, but I don't know much about table formatting and might have missed some subtleties. At the very least, it seems to preserve the style if it was chosen from Excel's built-in list of table styles.

Resources