How to extract pivot table data source range using VBA - excel

I have created a pivot table using the data in another sheet. My pivot table is working fine. When ever there is a data change when I refresh the table its captured correctly.
I tried to access the source data details for this pivot table using vba. By using the following code
Set PT = Worksheets("PivotTable").PivotTables("PivotTable1")
Debug.Print PT.SourceData
It gave me the result
Data!C1:C6
It gave the sheet name properly but not the data range. Where am I going wrong.
Is there any other alternative available to get the source data details.
Thanks in advance.

You're pulling the R1C1 reference. That can be changed with application.convertformula. Note that because you're using the entire column, it would make sense to reduce the scope of range within the sheet's usedrange area.See below how it would work.
Set PT = Worksheets("PivotTable").PivotTables("PivotTable1")
Set rngSourse = Range(Application.ConvertFormula(pt.SourceData, xlR1C1, xlA1))
debug.print rngSourse.address
Set WSsource = rngSourse.Worksheet
Set rngSourse = Intersect(WSsource.UsedRange, rngSourse) 'now it's only the used
debug.print rngSourse.address

Related

display Excel PivotTable Data Source as cellvalue

I am trying to find a way to display PivotTable Data Source in excel worksheet. I know we can manually view the Data source by clicking on PivotTable Tools Analyze > Change Data Source > Change Data source to display source in a separate window. I would like to know if it is possible dynamically display the source value as text in a linked cell(sample cell F4 below).
It can be one way relationship, meaning changing PivotTable Data Source, the display cell should be automatically updated, but changing the cell value in display cell does not necessary lead to change in PivotTable Data source. (**but if it change be done for both directions, would be even better.)
welcome both VBA and non-VBA solutions.
Any suggestions are much appreciated.
THANK YOU VERY MUCH!
Create this function.
Function PivotTableSource(myPivot As String) As String
Dim rawSource As String
Dim a1Source As String
Dim bracket As Long
Application.Volatile
rawSource = ActiveSheet.PivotTables(myPivot).SourceData
a1Source = Application.ConvertFormula(rawSource, xlR1C1, xlA1)
bracket = InStr(1, a1Source, "]")
PivotTableSource = "=" & Mid(a1Source, bracket + 1)
End Function
Then put =PivotTableSource("PivotTable1") in cell F4. PivotTable1 is the default name of the first Pivot Table created in a spreadsheet. Change it if your pivot table is named something else.
It would be interesting to look at the events associated to the PivotTable Data Source, in the Microsoft documentation for example.
If there is an event triggered on the Data Source change, you can create a handler to update the value in the F4 cell.
Recording a macro while changing the Data Source of the PivotTable might also give some interesting hints.

How to refer to a structured table without referring to its sheet in VBA

In VBA I know that I can refer to a structured table via this way:
Set Tbl = Sheets("MySheetName").ListObjects("MyTblName")
Then do Tbl.XXX where .XXX can be .Name, .Range, etc.
However, I want to refer to this table without referring to the Sheet name, so that the macro does not break if the sheet name changes.
Is this possible?
After some research I found something that is not a perfect solution.
You can make use of the Range function in VBA like this:
Set tbl = Range("TableName[#All]")
However this is not a ListObject but a Range. You can also do other references like:
the body of the structured table (excluding headers)
Range("TableName")
Column called "MyColumn" of the body
Range("TableName[MyColumn]")
etc.
Then you call something like:
tbl.ListObject to refer to the structured table where the range is found.
The cool thing is that Range() will always work on the ActiveWorkbook, so you can be in WorkBook B and open a macro in Workbook A and it will still run on Workbook B
Source: https://peltiertech.com/structured-referencing-excel-tables/
Why not refer to the sheet's "internal" name instead of its visible name?
If your table is on the ActiveSheet, you can use it like:
Set Tbl = ActiveSheet.ListObjects("MyTblName")
If you would like to refer to a table (name "tbl_Function") in an unknown worksheet, here is what you can do:
Set rng4= Range("tbl_Function[#All]") ' range of table
sh = rng4.Parent.Name ' name of the worksheet where the table is placed
tbl = Sheets(sh).ListObjects("tbl_Function").Range.Value ' take the whole table
Hope it helps. Piotr

Combine Multiple Tables Rows Into Master Table

Happy Monday Everyone!
Have a question and hope you can help. I have a budget spreadsheet that has a budget tab. On this tab is about 8 tables broken down into different categories. Every table in the tab has the exact same columns. Is there a non-vbscript/marco way to create a master table that combines all of the tables into a single table in a different tab. This seems like it would be a no brainer but I have tried everything I can think of and find online and there doesn't seem to be a decent solution without an addon called power query.
I know you asked for a non VBA way, but for completeness I'm adding another answer that also has a VBA solution, because it's dead simple, it's blazingly fast, and it's generic. All you need to do is cut and paste this code into a standard code module, add a button and assign it to trigger the calling routine, give your source tables a name includes the full name of the summary table, and you're good to go.
Sub CombineTables(loDest As ListObject, Optional lcSource As ListColumn)
Dim ws As Worksheet
Dim lo As ListObject
Dim lc As ListColumn
Dim rDest As Range
Dim lDestRows As Long
Dim lSourceRows As Long
Application.ScreenUpdating = False
If lcSource Is Nothing Then Set lcSource = loDest.ListColumns(1)
If loDest.ListRows.Count > 0 Then loDest.DataBodyRange.Delete
For Each ws In ActiveWorkbook.Worksheets
For Each lo In ws.ListObjects
If lo <> loDest Then
With lo
If InStr(.Name, loDest.Name & "_") > 0 Then
On Error Resume Next
lDestRows = loDest.ListRows.Count
On Error GoTo 0
lSourceRows = .ListRows.Count
If lSourceRows > 0 Then
'Work out where we want to paste the data to
Set rDest = loDest.HeaderRowRange.Offset(1 + lDestRows).Resize(lSourceRows)
'Resize the destination table
loDest.Resize loDest.Range.Resize(1 + lSourceRows + lDestRows)
For Each lc In .ListColumns
Intersect(loDest.ListColumns(lc.Name).Range.EntireColumn, rDest).Value2 = lc.DataBodyRange.Value
Next lc
Set lc = Nothing
On Error Resume Next
Set lc = .ListColumns(lcSource.Name)
On Error GoTo 0
If lc Is Nothing Then Intersect(lcSource.Range, rDest.EntireRow).Value2 = ws.Name
End If
End If
End With
End If
Next lo
Next ws
Application.ScreenUpdating = True
End Sub
And here's the caller:
Sub CombineTables_Caller()
CombineTables [SomeName].ListObject, [SomeName].ListObject.ListColumns("Source")
End Sub
When I push that button, the code will look throughout the workbook for any tables who's names contain the name of the Destination table (in this case the Table called "SomeName"), and then bring their data through. So if you are adding new tabes, then as long as you prefix their Table names with the name of the destination table, they will be included. Any other tables (such as the one called 'DifferentName' will be ignored.
...and here's the result:
You can use the functionality of the pivottable wizard to consolidate multiple ranges (which are your tables) together into one pivottable.
When it prompts for you to add your ranges use the table names with the following syntax: Table4[#All]
You need the [#All] to get all the data associated with the table. Just repeat this for each of your tables names you want to consolidate.
Full description i have given in my answer here:
combining data from two sheets and generating pivot table in another sheet
Note: If you want to keep the original table names or table numbers you will need to select the option:
1) "I will create the Page Fields"
2) Enter the Ranges using the table name e.g. Table4[#All]
3) Select how many page fields do you want 1-4 and add item label used to identify the selected ranges below e.g. Table4.
I am not sure if 4 items is the maximum or if this can be extended through VBA. However you can also use PowerQuery or UnionQuery.
The following quotes are from here: http://www.contextures.com/xlPivot08.html
I include some outline in case links are lost.
PowerQuery:
If you have a version of Excel that supports Microsoft's Power Query add-in, you can use it to combine the data in two or more tables. The tables can be in the same workbook, or in different files.
http://www.contextures.com/xlPivot08.html#videopowerquery
Union Query:
If you can't combine your data on a single worksheet, another solution is to create named ranges in an Excel file, and use Microsoft Query (MS Query) to combine the data.
http://www.contextures.com/xlPivot08.html#union01
If you have Excel 2013 or later, then this is the perfect excuse to go play with PowerQuery, which is now called 'Get & Transform' in the ribbon. You can see something very similar to your requirement in my answer at excel indirect function to read dates and return dynamic values
I strongly suggest you go and look at that thread...even if for some reason you can't use PowerQuery for this particular challenge, because I reckon it's worth seeing just how simple it is to mash together identical tables using PowerQuery, even if just for future reference. It's basically a VBA developer in a box. It's a VBA gimp!

Dynamic range for Linked Excel Object/range in Word

I have a Excel Pivot table linked my Word report.
The Pivot table will growth when getting more data. However, when the Pivot table size change, it doesn't be reflected in the Word file. The word file always display the original selected range. So I have to update the link range manually.
Is there is a way to fix this issue or simply the effort?
Many thanks.
Below is my solution to fix this issue.
1. Create a Named Range for the Pivot Table.
2. Change the Linked Range absolute address in Word file to the Named Range
================
Note for 1:
create named range for a Pivot table can be done via Excel "Offset" function.
However, the Offset function is not perfect when there are more data in the same sheet.
so I create my own Excel function to that.
Function PVRange1(Sheet_Name, Pivot_Name) As Range
'Returns a Range object that represents the range containing the entire PivotTable report, but doesn’t include page fields.
'
Dim pvt As PivotTable
Set pvt = Worksheets(Sheet_Name).PivotTables(Pivot_Name)
Set PVRange1 = pvt.TableRange1
End Function
Function PVRange2(Sheet_Name, Pivot_Name) As Range
'Returns a Range object that represents the range containing the entire PivotTable report, including page fields.
Dim pvt As PivotTable
Set pvt = Worksheets(Sheet_Name).PivotTables(Pivot_Name)
Set PVRange2 = pvt.TableRange2
End Function

Multiple Pivot Charts SetSourceData Error

I have multiple pivot charts each with their own pivot table on separate worksheets in Excel 2002.
When I try to generate these charts with VBA with the following code:
Set cht = Charts.Add(After:=Worksheets("Setup"))
With cht
' we use named ranges here
.SetSourceData Source:=range(tblName)
.Name = chtName
....
where tblName is a named range just created a few lines before, the code runs fine if there is only one table and chart generate but gives me a run time error 1004: "The source data of a PivotChart report cannot be changed..." if I try to generate pivot table and chart set one after another.
Going to Insert -> Name -> Define, the list of named ranges created seems to be correct.
What is the correct way of setting the source data for a pivot chart with a dynamic range?
I think you might be trying to do too many things at once.
If the Data Source is going to change, I wouldn't use a Pivot Chart.
Use a pivot table, create the chart at runtime (like your example). Build your chart of the results of the pivot table.
This piece of code assumes that you have only one pivot table per sheet and the pivot table starts on Cell A1:
Sheets(wsName).Select
Range("A1").Select
Set cht = Charts.Add(after:=Worksheets(Worksheets.Count))
With cht
.SetSourceData Sheets(wsName).Range("A1")
.Name = chtName
...
Also changing "Worksheets.Count" to a specific worksheet name seems to trigger that error as well.

Resources