I wrote the following sub for a workbook containing 12 pivot tables (PT) in 6 sheets, all pointing to the same external source (another workbook). It works fine, except that if I wish to manually Refresh one pivot, Excel tells me I need to open the source file. If I then open the pivot's source file, the refresh works OK.
I would prefer to have the pivot cache refreshed in the background, like it once was. What am I missing ?
Sub ChangePivotSourceData(src As String)
Dim pt As PivotTable, wks As Worksheet, pc As PivotCache
'update #1 pt in PIVOT AF
Sheet2.PivotTables(1).ChangePivotCache ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=src)
'adjust all others
For Each wks In ThisWorkbook.Worksheets
Debug.Print Now, wks.Name
For Each pt In wks.PivotTables
Debug.Print Now, pt.Name
pt.CacheIndex = Sheet2.PivotTables(1).CacheIndex
pt.RefreshTable
Next pt
Next wks
Debug.Print Now, "ChangePivotSourceData complete"
End Sub
The sub is called like this:
Workbooks.Open fn, False, True
shMenu.Range("c5").Value = fn
Application.Calculation = xlCalculationManual
'change source of ALL pivots
ChangePivotSourceData fn & "!feesIn" 'feesIn is a named range
Took me a few hours but I found a solution.
The problem is that - at first sight - you can't create a connection to an Excel range. You must have a whole sheet, or a table. In my case, the source data starts at B28 and could not be converted into a table. So I manually created the connection pointing to the whole sheet, bringing back of few rows of garbage. I then went the data/properties/definition, and
- I changed the Command type from Default to SQL
- I changed the Command text to a SQL statement like this: select * from [mySheet$b28:bt4000] where ccy is not null (note the required $ at end of sheet name)
Then I managed to get all pivots to point to that connection and finally I wrote a function to allow changing the connection source workbook name:
With ThisWorkbook.PivotCaches(1)
adoConn = Split(.Connection, ";")
adoConn(3) = "Data Source=" & fn
.Connection = Join(adoConn, ";")
.Refresh
'Debug.Print Now, .CommandText 'sql statement
End With
This way the refreshes are fast, and indeed I only need to refresh the connection to have all 12 PT updated.
Related
I have an excel file with 4 sheets. Each sheet contains a pivot table that connects to an Oracle database. I need all pivot tables to update automatically at 4 am. To do this I have a macro. The problem is the macro asks me to select a data source manually. Is there a way the macro select the data source automatically?
When I execute the macro, it shows me this window 4 times:
And then:
I need the macro select the one that is marked (PRODUCCION DWH).
This is the macro:
Sub Actualiza_Reporte()
Dim pt As PivotTable
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
For Each pt In ws.PivotTables
pt.RefreshTable
Next pt
Next ws
ThisWorkbook.Save ' Guardamos el archivo
ThisWorkbook.Close ' Para cerrar el archivo
Application.Quit ' Para cerrar Excel
End Sub
I need to update the 4 sheets automatically, without asking me to select the data source.
Thanks and regards.
Besides using macros, you could also do it with power query which is included in Excel 2016 and higher by default:
Select Data, then New Query, then Databases, then Oracle and create a connection to Oracle.
Then you only need to set the refreshing intervall like this:
Click Data again, then Connections, then Settings, then Update after X minutes.
If you want control the exact time of the oracle power query update, just configure this macro:
Sub RefreshQuery()
Dim con As WorkbookConnection
Dim Cname As String
For Each con In ActiveWorkbook.Connections
If Left(con.name, 8) = "Query - " Then
Cname = con.name
With ActiveWorkbook.Connections(Cname).OLEDBConnection
.BackgroundQuery = False 'or true, up to you
.Refresh
End With
End If
Next
End Sub
Code found here: https://stackoverflow.com/a/38653892/11971785
I have a pivot table in my Sheet1 connected to external sources which is also an excel sheet. All i am trying to do is to get a date and time stamp whenever someone refreshes pivot table.
I get an error Object doesn't support this property or method.
Private Sub Refresh_Click()
Dim PT As PivotTable
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
For Each PT In WS.PivotTables
PT.RefreshTable
WS.Sheets("Month-to-Date").Range("P5") = TimeValue(Now)
Next PT
Next WS
End Sub
The problem is that WS is a Worksheet and a Worksheet does not support another Worksheet as a property.
Worksheets are properties of Workbooks so
ThisWorkbook.Sheets("Month-to-Date").Range("P5") = TimeValue(Now)
Fixes the problem
There is a fancy built-in event in Excel VBA for this. In the worksheet of the pivot table, select the event PivotTableUpdate (Event Documentation):
As far as probably there would be more than 1 pivot tables on the worksheet, it is a good idea to check which one is the refreshed one, using its name:
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Select Case Target.Name
Case "PivotTable2"
Debug.Print "Write date somewhere "; Format(Now, "DD-MM-YYYY")
Case Else
Debug.Print "Not PivotTable2"
End Select
End Sub
"DateStamp" is obtained through Format(Now, "DD-MM-YYYY") and printed to the immediate window (Ctrl+G). Instead of printing there, it is a possible option to write it to a server or to a separate worksheet, getting the last cell of a row like this:
Case "PivotTable2"
Worksheets(2).Cells(lastCell, 1) = Format(Now, "DD-MM-YYYY")
I have a workbook (A) that pulls up another (B), copies values from wb B and pastes values to wb A (no table, no formulas; just data).
ActiveWorkbook.Sheets("Sheet1").Range("A1:F" & lonTempWBLastRow).Copy shtNewMonth.Range("A1")
I then attempt to create a table with:
Set NewMonthTable = wbPDRC.ListObjects.Add(xlSrcRange, Range("A1:F" & lonTempWBLastRow), , xlYes)
but get error 1004: a table cannot overlap a range that contains a PivotTable, query results, protected cells, or another table. I delete the named range from the sheet so it's not a named range issue. There's no Pivot, query results, protected cells, or table. I even tried to run a loop on unlisting all tables from the sheet but the loop immediately exits as it doesn't see a table on the sheet. I also attempted to run the table code first on wb B then transfer it as a table VS values but I get the same error on that sheet when attempting this way. If I try to make the table in Excel without VBA, the Format As Table dialog box stays put after hitting "OK" a number of times. There is a connection in wb B which I delete via code prior to transferring the data and have verified once it pastes to wb A that the connection is not there. Ideas?
I am guessing, that the problem is that the table already exists, thus, it is not ok to make a new one. Try this piece of code, changing "Table1" to the name of your table:
Option Explicit
Public Sub TestMe()
Dim newTable As Object
Dim someRange As Range
With ThisWorkbook.Worksheets(1)
Set someRange = .Range("A1:F" & 10)
If Not TableExists("Table1", .Cells.Parent) Then
Set newTable = .ListObjects.Add(xlSrcRange, someRange, , xlYes)
End If
End With
End Sub
Public Function TableExists(tableName As String, ws As Worksheet) As Boolean
On Error GoTo TableExists_Error
If ws.ListObjects(tableName).Name = vbNullString Then
End If
TableExists = True
On Error GoTo 0
Exit Function
TableExists_Error:
TableExists = False
End Function
Or simply open a new Excel file and run it. The A1:F10 range would be formatted.
VBA Excel check if a particular table exist using table name
To make this work I had to create a fake, blank table as soon as the sheet was created then paste the data over to it.
I need to safely transfer the cache of a Pivot Table on an Excel File, into a pivot on a different file. How can I do this?
This is the code I'm using now
(Notice this method works even if the Source pivot Data Source has been eliminated):
Public Sub TransferPivotCache(Source As PivotTable, Target As PivotTable)
Dim TempSheet As Worksheet
Set TempSheet = ThisWorkbook.Sheets.Add
Source.TableRange2.Copy Destination:=TempSheet.Range("A1")
Target.CacheIndex = TempSheet.PivotTables(1).CacheIndex
TempSheet.Delete
End Sub
However when the pivot I'm importing is too big I get the error "Not enough memory" when modifying the cache index property. And afterwards, even the file closes and if I try to reopen it, it's corrupted. Is there a better way to transfer a Pivot Cache between pivot tables?
If your goal it to update another pivot table targeting the same data, then another way would be to create a new PivotCache pointing to the same source. This way, the targeted workbook will build the same PivotCache without the need to copy the DataTable, which is probably the cause of your memory issue.
Public Sub TransferPivotCache(source As PivotTable, target As PivotTable)
Dim pivCache As PivotCache, sh As Worksheet, rgData As Range, refData
' convert the `SourceData` from `xlR1C1` to `xlA1` '
source.Parent.Activate
refData = Application.ConvertFormula(source.SourceData, xlR1C1, xlA1, xlAbsolute)
If IsError(refData) Then refData = source.SourceData
If Not IsError(source.Parent.Evaluate(refData)) Then
' create a new pivot cache from the data source if it exists '
Set rgData = source.Parent.Evaluate(refData)
If Not rgData.ListObject Is Nothing Then Set rgData = rgData.ListObject.Range
Set pivCache = target.Parent.Parent.PivotCaches.Create( _
XlPivotTableSourceType.xlDatabase, _
rgData.Address(external:=True))
pivCache.EnableRefresh = False
target.ChangePivotCache pivCache
Else
' copy the pivot cache since the data source no longer exists '
Set sh = source.Parent.Parent.Sheets.Add
source.PivotCache.CreatePivotTable sh.Cells(1, 1)
sh.Move after:=target.Parent ' moves the temp sheet to targeted workbook '
' replace the pivot cache '
target.PivotCache.EnableRefresh = True
target.CacheIndex = target.Parent.Next.PivotTables(1).CacheIndex
target.PivotCache.EnableRefresh = False
'remove the temp sheet '
target.Parent.Next.Delete
End If
End Sub
I was not able to reproduce the resource issue with my Excel Professional 2010... But have you tried this simpler possibility?:
Public Sub TransferPivotCache(SourcePivot As PivotTable, TargetPivot As PivotTable)
TargetPivot.CacheIndex = SourcePivot.CacheIndex
End Sub
It looks like it does the same (at least within the same workbook), and it avoids creating a whole new sheet.
In Microsoft Excel, when refreshing my data sources (clicking "Refresh All" in the "Connections" block under the "Data" tab), it provides me with a message saying that it can't find the data source for a PivotTable - this is understandable, as I deleted the Sheet that contained the data.
The problem is now finding the specific PivotTable to delete it, as I don't want to receive the message every time I refresh my data sources.
Any ideas?
As a simple, one-off test, I think this will work for you. It displays a message and selects the offending pivot table. Just put this code in a module in the workbook with the pivot tables:
Sub FindDatalessPivot()
Dim ws As Excel.Worksheet
Dim pt As Excel.PivotTable
For Each ws In ThisWorkbook.Worksheets
For Each pt In ws.PivotTables
With pt
On Error Resume Next
.RefreshTable
If Err.Number <> 0 Then
ws.Activate
.DataBodyRange.Select
MsgBox .Name & " in " & ws.Name & " is disconnected."
End If
On Error GoTo 0
End With
Next pt
Next ws
End Sub
Of course, you could do this by hand as well, by refreshing each pivot table individually.
I also note, that at least in Excel 2010, when I Refresh All a dialog pops up telling me which pivot table isn't connecting.