I have an Excel document with 4 Worksheets.
On Sheet1 I set my start & end dates for my data.
On Sheet2 is the data itself (provided by an external SQL database).
On Sheet3 & Sheet4 are PivotTables that use the second sheets data as their source.
I have created a VBA macro button on Sheet1 to refresh all.
I'll change my date range on Sheet1 then click the button but it only refreshes the data on Sheet2 and not the PivotTables on Sheet3 & Sheet4. I have to click the button a second time to refresh the PivotTables with the new data.
Here is the VBA code:
Sub Button2_Click()
Application.ScreenUpdating = False
ActiveWorkbook.RefreshAll
Application.ScreenUpdating = True
End Sub
Even manually using the Refresh All button has the same outcome.
It seems when you do a refresh all it is trying to refresh everything in parallel, probably to save time. However, I think since you have pivot tables which are dependent on data which needs to refresh from the DB, you have to ensure that your external data is refreshed prior to attempting to refresh the pivot tables.
I was able to reproduce the issue and doing the below resolved it for me. Just have to replace "Query1" with the name of your query.
ActiveSheet.ListObjects("Query1").QueryTable.Refresh BackgroundQuery:=False
For Each pc In ActiveWorkbook.PivotCaches
pc.Refresh
Next
Edit:
To get the query name, you can go to the "Data" tab on your ribbon you should see a button that says "Queries & Connections" clicking on that will expand a pane on the right side of the excel screen. In that pane clicking on the Queries tab on the top will give you a list of your queries that are set up
Screenshot of my QueryTable name
Related
There are 3 sheets in my excel file.
One (Qry Results) is Query, the next one (Qry) is importing the data from Query by formula, the last one (Results) has a Pivot table based on Qry data.
Qry Results needs to be refreshed in VBA. It is working fine.
Qry data is udpated automatically by formula.
If Qry data is 100, but I entered formula in 150 lines.
When I run VBA by step by step, the PIVOT is refresh properly. But when I run automatically, the pivot is not refreshing.
`Refresh Query
Sheets("Qry Results").Select
Range("A4").Select
ActiveWorkbook.RefreshAll
`Refresh Pivot
Sheets("Result").Select
Range("A12").Select
ActiveWorkbook.RefreshAll
Or
ActiveSheet.PivotTables("PivotTable1").PivotCache.Refresh
You may have background refresh enabled in the Power Query. With this setting active, the Power Query starts to refresh, but the pivot table refresh is kicked off basically at the same time, before the new data is loaded by the Power Query.
To remedy that, you can disable background refresh on the Power Query. Right-click the Power Query in the side panel and select Properties. Untick the box.
Now the pivot table refresh will run only after the Power Query refresh has finished.
-- And, by the way, there is no need to select anything before running ActiveWorkbook.RefreshAll and there is no need to refresh all twice. RefreshAll refreshes everything. If you want to use a particular order, then you can refresh one by one with code like this:
ActiveWorkbook.Connections("Query - Table1").Refresh
ThisWorkbook.Worksheets("Sheet2").PivotTables("PivotTable1").PivotCache.Refresh
Maybe you could try something like this (in order to wait for the query refresh to happen):
Sub RefreshQuery()
'Code to refresh query here
End Sub
Then, in the sheet with the query results:
Private Sub Worksheet_Change(ByVal Target As Range)
'Code to update pivot here
End Sub
I have a slicer which is used to manipulate a PivotTable. The PivotTable is a list of filters. Ultimately, the slicers + PivotTable are used to retrieve data and populate a worksheet for end users.
Issue
I recently added a combobox that autocompletes data so end users could quickly type what they were looking for rather than spend the time scrolling through each slicer and selecting appropriate options. As I have been testing the sheet, I noticed a blank row has appeared at the top of one of my slicers. How do I remove this blank row?
Attempts
I checked the data source for the PivotTable + slicers, there are no blank rows. I did a GoTo --> Blanks to try and isolate any blank cells (no blank cells in the data). I refreshed the data source and I also changed the data source to what it should be, the blank row in the slicer is still there, despite no blanks in my PivotTable data. I also went to Slicer Settings and checked 'Hide items with no data' but still, the blank entry in the slicer persists.
I would add that vba code that manipulates the PivotTable isn't modifying the slicers in any way. In my vba I call:
When I lock the sheet:
Me.Protect DrawingObjects:=False, UserInterfaceOnly:=True, AllowUsingPivotTables:=True
In the ComboBox1_Click() event after the user selects an entry from the autocomplete dropdown:
ActiveSheet.PivotTables("PivotTable").PivotFields("Portfolio").CurrentPage = _
ComboBox1.Value
And when a user clicks a 'Clear Filters' button I call:
ActiveWorkbook.ActiveSheet.PivotTables("PivotTable").ClearAllFilters
Those are the only manipulations of the PivotTable within my vba code.
I have a spreadsheet with multiple tables, where the data is pulled from an external data source (SQL database). The connections/tables refresh by changing an option in a drop down box and then pressing a button to run a VBA.
Attached to each of these tables is a pivot table. The pivot tables don't refresh with the tables. If I try pressing refresh all I get the error;
'Data Source name not found and no default driver specified'
However if I go through the spreadsheet and hit refresh on each individual pivot table they update without the error.
So either I need some way to get the pivot tables to refresh with the tables or have a button that refreshes only the pivot tables and not the external data connections.
Any ideas appreciated, I don't know where to begin with this one!
You can refresh a given PivotTable on Sheet1 like this:
Sheet1.PivotTables(1).RefreshTable
That will refresh the first PivotTable on Sheet1. Change the index number for a different one.
Or...
You can refresh all of the PivotTables on a give sheet by calling this routine:
Sub RefreshPivotTables(ws As Worksheet)
Dim pt As PivotTable
For Each pt In ws.PivotTables
pt.RefreshTable
Next
End Sub
You would call the above routine from the same code associated with the button mentioned in your question that updates the tables.
Or...
If you'd like to update all of the PivotTables in a workbook, you can use this version of the routine:
Sub RefreshPivotTables(wb As Workbook)
Dim ws As Worksheet
Dim pt As PivotTable
For Each ws In wb.Worksheets
For Each pt In ws.PivotTables
pt.RefreshTable
Next
Next
End Sub
You would call this version like so:
RefreshPivotTables ThisWorkbook
Becky: Any reason you don't populate those PivotTables directly from the SQL query? Unless you need those tables there for some reason I'd suggest just ditch 'em, and simply turn the data directly into PivotTables. Otherwise you're effectively saving the same data in the file twice. (Or three times, if you haven't unchecked "Save source data with file" under PivotTable>Data>Options.
If you do need to refresh them - and if there are multiple PivotTables connected to each Table - then it is more efficient to iterate through the underlying PivotCaches and refresh any where the sourcetype is an Excel Range. In VBA speak that's where pc.SourceType = xlDatabase
Sub Refresh_PivotCaches()
Dim pc As PivotCache
For Each pc In ActiveWorkbook.PivotCaches
If pc.SourceType = xlDatabase Then pc.Refresh
Next pc
End Sub
If you instead iterate through each and every PivotTable, then if multiple PivotTables are connected to one PivotCache you end up doing more refreshes than you need. For instance, if you have 10 PivotTables that all point to the same table, you do not need to refresh those 10 PivotTables individually. Rather, you just need to refresh the one PivotCache that they all share. If you were to refresh those 10 PivotTables individually, then in effect you are refreshing each of those 10 PivotTables 10 times.
Granted, if your PivotTables are small you won't notice any difference between my code and Excel Heros.
I added the following at the end of my code which seemed to work fine.
Dim PT As PivotTable
Dim WSH As Worksheet
For Each WSH In ThisWorkbook.Worksheets
For Each PT In WSH.PivotTables
PT.RefreshTable
Next PT
Next WSH
I know this is an old post, but sharing in case this helps anyone researching this like I was -- This may be new to Excel 2016 (I don't have access to older versions currently to test), however I found that you can disable the "Refresh with Refresh All" setting on your external data sources. This will then allow you to use the "Refresh All" from the Data Tab to update all your pivot tables at once, without updating the external data source query again:
Data Tab > Connections Section > Open Connections
Select a connection in the Workbook Connections window and click Properties...
In the properties window, uncheck the box for "Refresh this connection on Refresh All"
Repeat for any additional External Connections you don't want to update automatically
I use this in a reporting macro by calling the manual query updates once:
(selecting a cell in each table created by a query)
ActiveWorkbook.Sheets("Completed").Select
Range("A2").Select
Selection.ListObject.QueryTable.Refresh BackgroundQuery:=False
And then calling refresh all as needed to update my pivot tables:
ActiveWorkbook.RefreshAll
I have an Excel 2010 workbook. One worksheet imports data from an external data connection (SQL query). I have also added additional columns to the worksheet to perform calculations on the data and to massage it a bit. The worksheet forms the backbone of the raw data used in the other worksheets.
I'd like to protect the worksheet to make it read-only (allowing sort, filter, pivot table usage). I know how to do this with the protect worksheet feature. But when the worksheet is protected, I can't use the Refresh button to refresh the data from the source and I want users to be able to do this. I was going to configure the connection properties to automatically refresh on open and allow manual refreshes.
Has anyone found an elegant way of enabling the protect worksheet functionality and enabling an external data refresh, without allowing users to change cell values themselves?
Based on Pankaj's suggestion I did the following (although I don't think it's very elegant and still think there must be a better way).
I created a new macro for the workbook.
Sub RefreshData()
'
' RefreshData Macro
'
Application.ScreenUpdating = False
Sheets("sheetname").Unprotect Password:="password"
ActiveWorkbook.Connections("connection name").Refresh
Sheets("sheetname").Protect _
Password:="password", _
UserInterfaceOnly:=True, _
AllowFiltering:=True, _
AllowSorting:=True, _
AllowUsingPivotTables:=True
End Sub
Then I opened up ThisWorkbook in the VBA Project and edited the Workbook Open routine.
Private Sub Workbook_Open()
RefreshData
End Sub
More info about the protection options can be found here: http://datapigtechnologies.com/blog/index.php/worksheet-protection-best-practice/
It works; the sheet is locked everytime the workbook is opened and a refresh of the data is performed. The UserInterfaceOnly property doesn't make a difference to the command to refresh the data (although it should to other macro events). You will still have to specifically unlock the spreadsheet, perform the data refresh and then lock the sheet again.
I added a form button onto one of the other sheets and linked it to my RefreshData macro so that the data can be refreshed manually, while the sheet is supposedly locked.
The other thing I did in the Connection Properties, was to remove the tick against the background refresh.
An easy way to do it is to add a custom button and write a macro. When user presses the toolbar custom button, the macro behind it will unprotect the sheet and refresh the external data and then protect the sheet (with screenupdate set as false obviously)
I would suggest to add the external query on another sheet, not protected, but that you would hide.
The data on the protected sheet would simply refer to the unprotected sheet.
I added the data connection to some unprotected sheets, then hid the sheets.
Unfortunately the connections then don't work even if the structure of the workbook is protected.
I cant believe I may need to release my code un-protected, there must be an industrial strength solution to this
I've got an Access 2007 database on which I have created around 15 SQL queries to process specific data, I have created a main frame navigation menu using menus in Access, I now need to extract all th queries to Excel using VBA code, I have managed to do this with the code below by creating a button and specifying this code to it.
Private Sub query1_Click()
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, "Total Users and Sessions", _
"C:\UsersandSessions.xls", , "Total Users & Sessions"
End Sub
Now my problem at the moment is that fine the query is exported to Excel, but it is done so without any formatting applied at all, I would like to add some formatting at least to the headers and maybe a title inside the spreadsheet, and one thing I dont really like is that all records are being started from the first cell. Also I would prefer that if I hit that button again in Access and the Excel spreadsheet has already exists with that query output then when clicked again it will write again to a the next available sheet.
Any suggestions or ideas a very welcome.
The short story, is you can't. You might be able to do some scripting on the Excel side to format the resulting file. If you want something pretty, you probably want to create a report.
You could, instead mount the excel sheet as a table, and then on a separated sheet in the excel file, reference the first sheet, and format the second sheet for viewing.
if you use DoCmd.TransferSpreadsheet and create an original and then edit it so that the formatting is correct, you can then run DoCmd.TransferSpreadsheet again and it will update the file with the values but keep the formatting.
However, if a human then changes the file by adding new tabs, or adding calculations, etc, then the DoCmd.TransferSpreadsheet will no longer work and will fail with an ugly error message. So what we do in our enviroment is DoCmd.TransferSpreadsheet to an original file with formatting, and follow that up in the VBA by copying the file to the users desktop, and then opening that copy so the user doesn't mess up the original source excel file.
This approach is a minimum code, clean, and easy to maintain solution. But it does require a extra "source" or original file to be hanging around. Works in Access 2007.
You also would like the results to end up on a new tab. Unfortunately, I think it will take some excel automation to do that. The VBA inside Acccess can call a function inside the VBA in Excel. That VBA could then copy the tabs as needed.
My idea would be a hybrid of Excel automation from Access and creating a template in Excel as well that would have a data table linked to your query.
To start create your data table in Excel. You can start three rows down and two columns to the right if you want or wherever. Go to your data tab and click access, find your db, choose your query you want to link to, choose table as the radio button but click properties next instead of ok, uncheck the enable background refresh, this part is critical ... under the definition tab in the connection string you will see a part that says Mode=Share Deny Write change that to Mode=Read, this will make sure that the query refreshes without errors from an MS Access VBA while the db is open and will keep your users from writing back to the db in case your query is a writeable query. Once you set that up you can adjust the table formatting however you choose from the table design tab and it will keep that formatting.
For the purposes of this we are going to assume you started the table in cell B4 ,and your named the worksheet CurrentDay, for purpose of the following VBA example be sure to replace that reference with your actual placement.
Next go back to Access and write your VBA first ensure that in your VBA window you have the reference to Microsoft Excel 12.0 Object Library is selected by going to Tools > References and selecting it from the alphabetical listing.
Create your sub as follows:
Sub query1_click()
Dim xl as Excel.Application
Dim wbk as Excel.Workbook
Dim wks as Excel.Worksheet
Dim RC as Integer
Dim CC as Integer
Set xl = New Excel.Application
Set wbk = xl.wbk.Open "X:\Filelocation\FileName.xlsx" 'name and path you saved the file you previously created
xl.Visible = True
'The above is not necessary but you may want to see your process work the first few times and it will be easier than going to task manager to end Excel if something fails.
RC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("B:B")) + 3 'This will count the rows of data in your table including your header so you can copy the data to another tab dynamically as the size of your table expands and shrinks we add 3 to it because we started at row 4 and we need the location of the last row of the record set.
CC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("4:4")) + 1 'This counts the header row and adds one space because we will use this as a location holder for our copy / paste function
Set wks = xl.wbk.Worksheets.Add
wks.Name = format(date(),"MM_dd_yy") 'this will name the tab with today's date... you can eliminate this step if you just want the sheets to be the generic Sheet1, Sheet2, etc.
With xl.wbk
.Worksheets("CurrentDay").Range(Cells(4,2),Cells(RC,CC)).Copy
.wks.PasteSpecial xlPasteValues 'This pastes the values so that the table links do not paste otherwise every tab would just refresh everyday.
.wks.PasteSpecial xlPasteFormats 'This gets your formatting.
.RefreshAll 'This will refresh your table
Wend
With xl
.Save
.Close False
.Quit
Wend
Set xl = Nothing
Set wbk = Nothing
Set wks = Nothing
End Sub
That should get you to have your data to not start on A1 of your sheets, save your old data each time, and automate the steps from access.