强制vba在继续之前等待sql查询执行

这似乎是一个相当普遍的问题,但我发现的解决scheme似乎没有工作。

我从SQL Server获取一些数据并将其复制到工作表中。 然后我想从新的数据中复制一个范围,并用它来做其他的事情。 所有这些都发生在一个单独的vba函数中。

我的问题是当函数从Excel运行时,它将移动到函数的第二部分,而不用等待查询返回所需的数据。

当然,当我从vba IDE运行它时,该function工作正常。

Dim a As New ADODB.Connection Dim r As New ADODB.Recordset a.Open (connStr) Set r = a.Execute(sqlstr) sht.Range("A2").CopyFromRecordset r 'please wait here until the proc has executed? checkData = sht.Range("A2").Value 

当我从Excel运行函数时,checkData总是空的,当我用F5运行它时,它总是有所需的数据。

这是否工作?

 Dim a As New ADODB.Connection Dim r As New ADODB.Recordset a.Open (connStr) Set r = a.Execute(sqlstr) Do 'Wait Loop Until Not r Is Nothing sht.Range("A2").CopyFromRecordset r checkData = sht.Range("A2").Value 

或者,如果失败了,你可以尝试testingr的一些属性,比如EOF或者BOF,如果发生错误,或者你得到一个意外的值,那么你知道数据还没有加载。 例如:

 Dim a As New ADODB.Connection Dim r As New ADODB.Recordset a.Open (connStr) Set r = a.Execute(sqlstr) On Error Resume Next Do Err.Clear r.EOF 'Put your test here, you might test rowcount or similar. 'I've simply asked for the EOF property and ignored the result, I'm 'not sure if this will work in your case. Some testing may be required. While Err.Num <> 0 On Error GoTo 0 'Or whatever you previously had this set to sht.Range("A2").CopyFromRecordset r checkData = sht.Range("A2").Value 

尝试使用:

 Application.CalculateUntilAsyncQueriesDone 

在执行SQL之后,但在复制RecordSet之前

 Set r = a.Execute(sqlstr) Application.CalculateUntilAsyncQueriesDone sht.Range("A2").CopyFromRecordset r 

这可能有帮助。 在代码中设置数据源,而不是在目标工作表上设置数据连接(Excel菜单数据|其他来源|等)。 一旦创build了一个名为“(默认)”的连接对象,可以沿着这些代码点击代码:

  With ActiveWorkbook .Connections("(Default)").OLEDBConnection.BackgroundQuery = False .Connections("(Default)").OLEDBConnection.CommandText = sqlstr .RefreshAll ' do more stuff ' will wait for .RefreshAll to complete because .BackgroundQuery = false End With 

我认为你需要一个r.movelast执行后,以确保所有的行都返回。

就像是

 Set r = a.Execute(sqlstr) If Not r.EOF Then r.MoveLast End If sht.Range("A2").CopyFromRecordset r 

沿着andy holaday的路线,我通过在外部数据范围属性中取消选中“启用后台刷新”来得到这个工作。 禁用此function将强制excel在查询运行时等待。

但是,如果没有logging集被返回,我发现这个代码将等到SQL代码返回之前去下一个VBA语句。 如果一个命令依赖于另一个命令,或者在继续之前需要创build一个完整的数据集,那么方便。

 Dim Con As ADODB.Connection Dim CmdTxt As String Set Con = New Connection Con.ConnectionString = ThisWorkbook.GetYourConnectString() Con.Open CmdTxt = "EXEC db.schema.StoredProc1 @Param1 = 'Yes'" ExecuteSql Con, CmdTxt, True, True CmdTxt = "EXEC db.schema.StoredProc2 @Param1 = 'No'" ExecuteSql Con, CmdTxt, True, True MsgBox "Both commands completed sequentially" 

ExecuteSql的代码是:

 Public Function ExecuteSql(Con As ADODB.Connection, sql As String, _ Optional StopOnError As Boolean = True, _ Optional WaitUntilDone As Boolean = False) As String Dim cmd As ADODB.Command Set cmd = New ADODB.Command With cmd .CommandType = 1 .CommandText = sql .ActiveConnection = Con If WaitUntilDone = True Then .CommandTimeout = 0 'set timeout to unlimited .Execute , , adExecuteNoRecords 'no records value speeds up internal code Else .Execute End If End With ExecuteSql = "" Exit Function