Preventing Excel PivotTable Page Items overwriting Cells above - excel

I have an Excel Workbook with a Sheet that contains some company template headers with a Pivot Table placed underneath.
This document is to be used as a template for pivot reports and the headers have to remain intact above the Pivot Table however when items are added to the Page Filters, the Pivot Table tries to expand upwards and ends up overwriting the header rows above.
I need the Pivot Table to expand down the page instead of up the page when Report Filters are added.

After looking to see if there are and settings that can be changed to make the pivot table expand down the page I looked into how the functionality could be scripted using VBA. Adding the below code to the Worksheet via the Visual Basic for Applications screen checks the location of the PivotTable on each update and then moves it up or down the page if Page Filters are added or removed from the report. Setting the StartLineLet & StartLineNum variables to the Cell Address that you want the top left corner of the pivot table or page items to remain at.
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Dim StartLineLet As String
Dim StartLineNum As Integer
Dim DataAddr() As String
Dim PageAddr() As String
StartLineLet = "B"
StartLineNum = 6
DataAddr = Split(Target.TableRange1.Cells(1).Address, "$")
PageAddr = Split(Target.TableRange2.Cells(1).Address, "$")
If PageAddr(2) <> StartLineNum Then
Target.Location = "$" & StartLineLet & "$" & (DataAddr(2) + (StartLineNum - PageAddr(2)))
End If
End Sub

You can also instruct the PivotTable (via PivotTable Options > Layout & Format) to display the report fields Down, Then Over by changing the Report filter fields per column, e.g. from zero to the value of three.
This will move the PivotTable with a limited amount of three rows down, and consequently start adding Report Fields to the right (in blocks of three rows)

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 do I generate multiple charts from the same template for different inputs / scenarios

I'm using Excel, and have some basic VBA / Macro knowledge. I have a reasonable large data set that updates each week. From that Im using a series of Index/match to generate a table that is 40 columns (dates) by 4 rows ( time series data) for a specific product. I have 15-20 different products, which often change. This 4x40 table is then used to generate a chart. Using this manually I can select the product with a drop down box (Data validation), my index / matches pull the correct data into the 4x40 table, and the chart for that product is shown. But I'd like to have a macro that will generate the chart for product 1, copy and paste as an image to a word doc, then do the same for product 2, and 3, and so on, and then save the word doc as a pdf for distribution.
An option would be to create 15-20 of the 4x40 tables, and 15-20 of the charts, and then just copy / paste all of them, but it would become a nightmare to maintain as the products change, and if formatting changes are requested, more than likely.
Without seeing your exact worksheet is hard to give an exact piece of code. However I made a workbook with a requirement similar to this recently.
As an outline of an answer you could consider using a loop to loop through your list of 15 - 20 products placing each of them within the cell which you currently have your data validation (ensuring you have removed any validation first) this would then update the index matches and also your chart.
Within that loop you could include some code to save the sheet as a pdf before moving on to the next product (or place the chart on a separate worksheet and reference this explicitly).
e.g if your validation is in cell A1 worksheet "Table" and your list of products is A2:A20 worksheet "Products" something like this will get you some of the way;
Sub save_charts()
Dim i As Long
Dim path As String
Dim product_name As String
Dim ws_name As String
Dim file_name As String
i = 2
path = Application.DefaultFilePath
Do Until Worksheets("Products").Cells(i, 1).Value = ""
If Worksheets("Products").Cells(i, 1).Value <> "" Then
product_name = Worksheets("Table").Cells(1, 1).Value
ws_name = product_name & " Chart"
file_name = path & "\" & ws_name
Worksheets("Table").Cells(1, 1).Value = Worksheets("Products").Cells(i, 1).Value
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
file_name, Quality:=xlQualityStandard, _
IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:= _
True
End If
i = i + 1
Loop
End Sub
I am aware that you mentioned copying this into word before exporting as pdf? Is this a requirement? As this code just uses Excel's native export to pdf functionality.
I hope this helps.
Cheers.
An alternative that will automatically generate all 20 charts with each refresh with 0 vba would be to do the following steps 1 time:
1. Create a pivot table and pivot table chart you need for a given product, eg filter it on a single product code, create the basic chart, put off formatting for now. The source data for this pivot table needs to include the data for all 20 products
In the source data for step 1, add another column called FilterID and set this by formula so that 1 = the data for the first product; 2, the second; 3, etc.
Go back to step 1 pivot table and add FilterID as a pivot filter, set it to 1, so only the first product appears on the chart
Format the chart to taste
Now copy the worksheet containing the pivot table and pivot chart 20 times
Increment the FilterID on each copy
The only vba you need at this point is to cycle through each worksheet with a valid chart and save to pdf

Auto expand Excel table with macro

I have an Excel document which pulls data from an Access database.
From here, the data is summarised in a Pivot Table.
It is then pulled into another table which makes it easier to read and filter.
The last table is formatted as a table and formulas are in place.
Depending on the data in the database, this table can reduce or expand the number of rows when refreshed.
When I run the macro to refresh the data and tables, I want to be able to automatically resize the table so all of the data is shown, but no extra blank rows appear at the bottom.
So far, I have the following code which looks up the Pivot Table sheet (Pivot) to determine the number of rows to display in the output sheet (Report):
Sub ResizeList()
Dim ws As Worksheet
Dim ob As ListObject
Dim Lrow1 As Long
Lrow1 = Sheets("Pivot").Cells(Rows.Count, "A").End(xlUp).Row
Set ws = ActiveWorkbook.Worksheets("Report")
Set ob = ws.ListObjects("Report_Table")
ob.Resize ob.Range.Resize(Lrow1)
End Sub
However, it only removes the table formatting (not the data) from the extra rows at the bottom when the table reduces in size.
Also, I get too many rows in the Report Table because of the header and total rows in the pivot.
Can someone help?

Pivot/Table filter activated through link from other table's cell value

I have a list of items to work through and some items require deeper analysis. Essentially I have two tables. The first shows production results and through filtering column U, I get a list of outliers as in the following image.
Table of outliers
The values displayed in column S then require further analysis for which a pivot chart has been set up. In this chart I filter the particular VRTY number to take a closer look.
Pivot Chart for analysis
Both sheets are contained in the same workbook and I essentially work with two windows open, but to go through the list I have to manually enter every single VRTY value in the pivot filter.
The table of the Pivot chart and the outlier table are not related and data sources are different.
In column S of the outlier table (VRTY) I would ideally turn the values into links that automatically set the pivot filter to this value when clicked.
I am a novice at VBA but from the research I've done this will be the only option - I just haven't come by an instructions how to achieve this particular function.
Instructions/ advice would be highly appreciated.
Sambo: Make sure the orientation of the 'Number' field in the PivotChart's underlying PivotTable is a PageField, and then put the below code in the Sheet code module that corresponds to the sheet where the Outliers PivotTable is:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim pf As PivotField
Dim pf_Slave As PivotField
Set pf = ActiveSheet.PivotTables("PivotTable1").PivotFields("VRTY")
Set pf_Slave = ActiveSheet.PivotTables("PivotTable2").PivotFields("number")
If Not Intersect(Target, pf.DataRange) Is Nothing Then
On Error Resume Next
pf_Slave.CurrentPage = CStr(Target)
On Error GoTo 0
End If
End Sub
Change "PivotTable1" and "PivotTable2" as appropriate.
By "Sheet code module" I mean this type of thing:

Select Newest Record and Create New Table of Unique Values in Excel

I have an Excel table that records vehicle progress through work stations within a business. A given work station may be visited more than once.
The vehicle license plate number (Reg No) is used to identify the vehicle, and the user adds a new row to the spreadsheet when the vehicle arrives at the next new work station. As well as the Reg No, each row also has a Record ID.
This workflow means that multiple record rows will be created for a given Reg No.
When all work on a vehicle is complete, the record is cut and archived on another worksheet.
Current Vehicle Table
What I want to create is a summary table on another worksheet tab, that displays all rows for vehicles in progress. Where a vehicle currently has a single record, I want to extract that record row, and where a vehicle has multiple records, I want to extract only the last (most recent) record row.
I want the summary to be a “live” reflection of the underpinning data sheet.
From searches I have found formula examples to Ignore Duplicates and Create New List of Unique Values in Excel but these pick the first duplicate value by default, not the last. Search results on “lookup last match” or “return last value” have in common that the user must define the item they are searching for.
I think I need something different because my list of Reg No is not static - it is continually being refreshed by Reg No’s being added and removed (archived).
Acknowledging and understanding Excel is not a database, but if I was thinking in database / SQL terms, my (noob) query might be something like:
SELECT row
WHERE Reg No is unique
AND Record ID is greatest
Do you know of any way to achieve the result I seek, in Excel?
You could use a PivotTable and a lookup formula to accomplish this. Below is some simplified data in an Excel Table (aka ListObject), and below that is a PivotTable with a suitable lookup formula down the right hand side.
The PivotTable has the Reg No in it as well as the RecordID field in the Values (aggregation) area, set on 'Max'. So basically it displays the maximum RecordID value for each Reg No, and then in the column to the right there's an INDEX/MATCH formula that looks up that RecordID back in the data entry table, and returns the associated Stage.
It's not quite live as you will need to refresh the PivotTable, and you need to ensure that you've copied the Lookup formula down far enough to handle the size of the PivotTable.
You can easily automate the refresh simply by putting a Worksheet_Activate event handler in the worksheet. Something like this:
Private Sub Worksheet_Activate()
Activesheet.PivotTables("PivotTable").PivotCache.Refresh
End Sub
Since we've now involved VBA, you might as well have some code that copies the formula down the requisite amount of rows beside the PivotTable. I'll whip something up in due course and post it here.
UPDATE:
I've written some code to slave a Table to a PivotTable, so that any change in the PivotTable's dimensions or placement will be reflected in the shadowing Table's dimensions and placement. This effectively gives us a way to add a calculated field to a PivotTable that can refer to something outside of that PivotTable, as we're doing here with the INDEX/MATCH lookup. Let's call that functionality a Calculated Table.
If the PivotTable grows, the Calculated Table will grow. If the PivotTable shrinks, the Calculated Table will shrink, and any redundant formulas in it will be deleted. Here's how that looks for your example: The top table is from the Input sheet, and the PivotTable and Calculated Table below it are from the Results sheet.
If I go to the Input sheet and add some more data, then when I switch back to the Results sheet, the PivotTable automatically gets updated with that new data and the Calculated Table automatically expands to accommodate the extra rows:
And here's the code I use to automate this:
Option Explicit
Private Sub Worksheet_Activate()
ActiveSheet.PivotTables("Report").PivotCache.Refresh
End Sub
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
If Target.Name = "Report" Then _
PT_SyncTable Target, ActiveSheet.ListObjects("SyncedTable")
End Sub
Sub PT_SyncTable(oPT As PivotTable, _
oLO As ListObject, _
Optional bIncludeTotal As Boolean = False)
Dim lLO As Long
Dim lPT As Long
'Make sure oLO is in same row
If oLO.Range.Cells(1).Row <> oPT.RowRange.Cells(1).Row Then
oLO.Range.Cut Intersect(oPT.RowRange.EntireRow, oLO.Range.EntireColumn).Cells(1, 1)
End If
'Resize oLO if required
lLO = oLO.Range.Rows.Count
lPT = oPT.RowRange.Rows.Count
If Not bIncludeTotal And oPT.ColumnGrand Then lPT = lPT - 1
If lLO <> lPT Then oLO.Resize oLO.Range.Resize(lPT)
'Clear any old data outside of oLO if it has shrunk
If lLO > lPT Then oLO.Range.Offset(oLO.Range.Rows.Count).Resize(lLO - lPT).ClearContents
End Sub
What's cool is that the code will automatically resize the Calculated Table whenever the PivotTable updates, and those updates are also triggered by you filtering on the PivotTable. So if you filter on just a couple of rego numbers, here's what you see:
You mentioned SQL in your question, so I thought you might be interested in a VBA solution using SQL:
'Assumes your data is on a sheet called "DataSheet", and you want the answers stored starting in cell A2 of a sheet called "Results")
Sub test()
Dim objConnection As ADODB.Connection
Dim objRecordset As ADODB.Recordset
Set objConnection = New ADODB.Connection
Set objRecordset = New ADODB.Recordset
objConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
objConnection.Open
sqlcommand = "SELECT LAST([Record ID]), " & _
"[Reg No], " & _
"LAST([Priority Level]), " & _
"LAST([Make]), " & _
"LAST([Current Stage]) " & _
"FROM [DataSheet$] GROUP BY [Reg No]"
objRecordset.Open sqlcommand, objConnection, adOpenStatic, adLockOptimistic, adCmdText
Sheets("Results").Range("A2").CopyFromRecordset objRecordset
End Sub
To use that, you will need to include References to the "Microsoft ActiveX Data Objects 6.1 Library" and "Microsoft ActiveX Data Objects Recordset 6.0 Library" in your VBA project. (At least, they're the ones I select.)

Resources