In Excel 2016 VBA, I'm refreshing several queries like this:
MyWorkbook.Connections(MyConnectionName).Refresh
After the code is done, and no errors are encountered, I see that the hourglass icons for most of the queries are still spinning for several seconds.
Is it possible to check for success AFTER all the refreshes are completed? I'm concerned that my code isn't going to know if an error happens after the code finishes but before the queries are done refreshing.
BTW I don't want to do a RefreshAll, because some of the queries are dependent on others (uses them as a source). I refresh them in a certain sequence so that dependent queries are refreshed after the queries they are dependent on.
UPDATE:
I see that the Connection objects have a read-only RefreshDate property, which at first glance looked like it could be used to do this check:
MyWorkbook.Connections(MyConnectionName).OLEDBConnection.RefreshDate
HOWEVER, it doesn't seem to be getting set. I get an error trying to check it. If I set a Variant variable to that RefreshDate property, the variable shows as "Empty". The source is a SQL server database.
Go to the Data tab on the Excel ribbon > Queries & Connections. This will open a pane on the right-hand side that shows the queries and any with errors will have a caution sign. Thank you Treacy!
A connection only query will not refresh unless there is another query that is dependent on it. If you want to refresh it, you must change it to output to the workbook or to the power pivot data model. Select an appropriate destination for your query results.
Automatically refresh data at regular intervalsSelect Data > Queries & Connections > Connections tab, right click a query in the list, and then select Properties. Click the Usage tab. Select the Refresh every check box, and then enter the number of minutes between each refresh operation.
You can also press Ctrl+Alt+F5 anywhere in the workbook. This command not only refreshes data connections, it also refreshes all pivot tables (which are a form of data connection).
The QueryTable
object exposes two events: BeforeRefresh
and AfterRefresh
.
You need to change your paradigm from procedural/imperative to event-driven.
Say you have this code in ThisWorkbook
(won't work in a standard procedural code module, because WithEvents
can only be in a class):
Option Explicit
Private WithEvents table As Excel.QueryTable
Private currentIndex As Long
Private tables As Variant
Private Sub table_AfterRefresh(ByVal Success As Boolean)
Debug.Print table.WorkbookConnection.Name & " refreshed. (success: " & Success & ")"
currentIndex = currentIndex + 1
If Success And currentIndex <= UBound(tables) Then
Set table = tables(currentIndex)
table.Refresh
End If
End Sub
Public Sub Test()
tables = Array(Sheet1.ListObjects(1).QueryTable, Sheet2.ListObjects(1).QueryTable)
currentIndex = 0
Set table = tables(currentIndex)
table.Refresh
End Sub
The tables
variable contains an array of QueryTable
objects, ordered in the order you wish to refresh them; the currentIndex
variable points to the index in that array, for the QueryTable
you want to act upon.
So when Test
runs, we initialize the tables
array with the QueryTable
objects we want to refresh, in the order we want to refresh them.
The implicit, event-driven loop begins when table.Refresh
is called and the QueryTable
fires its AfterRefresh
event: then we report success, and update the event-provider table
object reference with the next QueryTable
in the array (only if the refresh was successful), and call its Refresh
method, which will fire AfterRefresh
again, until the entire array has been traversed or one of them failed to update.
Just found this solution at Execute code after a data connection is refreshed
The bottom line is: Excel refreshes data connection in the background and thus the rest of the code is executed without interruption.
Solution: set BackgroundQuery
property to False
Example:
For Each cnct In ThisWorkbook.Connections
cnct.ODBCConnection.BackgroundQuery = False
Next cnct
Possible problem: don't know which connection it is...
Remedy: case... when...
Dim cnct as WorkbookConnection ' if option explicit
' ODBC and OLE DB
For Each cnct In ThisWorkbook.Connections
Select case cnct.type
case xlconnectiontypeodbc
cnct.ODBCConnection.BackgroundQuery = False
case xlconnectiontypeoledb
cnct.OledbConnection.BackgroundQuery = False
end select
Next cnct
As you can see, code above only deals with ODBC and OLE DB. Depending on what types of data connection you are using, you can expand the select case clause. Unless changed, once run, connection's BackgroundQuery
will remain off.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With