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

时间:2012-07-12 14:04:41

标签: excel vba ado

这似乎是一个相当普遍的问题,但我找到的解决方案似乎都没有。

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

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

当我从vba IDE运行它时,该功能正常。

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运行它时,它始终具有所需的数据。

5 个答案:

答案 0 :(得分:10)

尝试使用:

Application.CalculateUntilAsyncQueriesDone

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

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

答案 1 :(得分:2)

这有用吗?

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

或者,如果此操作失败,您可以尝试测试r的某些属性,如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

答案 2 :(得分:2)

这可能会有所帮助。不是在代码中设置数据源,而是在目标工作表上将其设置为数据连接(Excel菜单Data | From Other Sources |等)。创建名为“(默认)”的连接对象后,可以按照以下行在代码中点击它:

  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

答案 3 :(得分:1)

我认为执行后需要r.movelast以确保返回所有行。

这样的东西
Set r = a.Execute(sqlstr)

If Not r.EOF Then
    r.MoveLast
End If

sht.Range("A2").CopyFromRecordset r

答案 4 :(得分:0)

但是如果没有返回记录集,我发现这段代码会等到SQL代码返回后再转到下一个VBA语句。当一个命令依赖于另一个命令时,或者如果您需要在继续之前创建整个数据集,则很方便。

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