Simple Solution
I had issues with some of my subs ending before the data had finished refreshing. If I understand correctly, that's what's happening with your sub. If so, you could try adding the line:
Application.CalculateUntilAsyncQueriesDone
Adding this line into my code directly after the refresh command worked for me.
Note: When I had the queries set as background queries, I occasionally got weird freeze/crash issues; so I would recommend turning off the background query option with any query you use the above code with.
Complex Solution
If the simple solution doesn't work, an alternative is to add a custom class that raises an event when the refresh is finished. The downside to this solution is that you may need to rewrite existing code to be triggered by an event, instead of having an in-line refresh command.
An example of such a custom class is below. Please note that there are some assumptions built into the code -- the most prominent being that the query is set to load onto a sheet in the workbook, and refresh in the background.
To use the custom class, insert a "class module" (this is not the same as a "Module"), and copy the code from the "class code" section below into the "class module". Next, in the code module for the worksheet holding the resulting query table, add this code:
Private WithEvents queryData As QueryClass
Public Sub querySetup()
Set queryData = New QueryClass
Set queryData.QryTble = Me.ListObjects("QueryName").QueryTable
End Sub
Private Sub queryData_Refreshed(ByVal RefreshSuccess As Boolean, ByVal isEmpty As Boolean)
End Sub
(Note that this code is assuming that the class module has been renamed to "QueryClass", and that the query was named "QueryName". If you used different names, you'll need to adjust the code accordingly.)
You can put custom code in the queryData_Refreshed
sub to happen after the query has finished refreshing. Note that the sub has two indicators -- if the query refreshed successfully, and if the query is empty (did not return any records). Then, to refresh the data, just call:
queryData.Refresh 5 'optional maximum of attempts; defualt is 1
These questions may also be helpful.
Class Code
Option Explicit
'class basics from Paul Renton, https://stackoverflow.com/questions/18136069/excel-vba-querytable-afterrefresh-function-not-being-called-after-refresh-comp
Private WithEvents mQryTble As Excel.QueryTable
Private RefreshFinished As Boolean
Private RefreshSuccessful As Boolean
Private attemptCount As Long
Private attemptMax As Long
Public Event Refreshed(ByVal RefreshSuccess As Boolean, ByVal isEmpty As Boolean)
Public Property Set QryTble(ByVal QryTable As QueryTable)
Set mQryTble = QryTable
End Property
Public Property Get QryTble() As QueryTable
Set QryTble = mQryTble
End Property
Public Property Get RefreshDone() As Boolean
RefreshDone = RefreshFinished
End Property
Public Property Get RefreshSuccess() As Boolean
RefreshSuccess = RefreshSuccessful
End Property
Private Sub mQryTble_AfterRefresh(ByVal Success As Boolean)
attemptCount = attemptCount + 1
If Success Or attemptCount = attemptMax Then
RefreshFinished = True
RefreshSuccessful = Success
RaiseEvent Refreshed(Success, mQryTble.ListObject.DataBodyRange Is Nothing)
Else
mQryTble.ListObject.Refresh
End If
End Sub
Public Sub Refresh(Optional attempts As Long = 1)
If Not mQryTble.Refreshing Then
RefreshFinished = False
attemptMax = attempts
mQryTble.ListObject.Refresh
End If
End Sub