4

这似乎是一个相当普遍的问题,但我发现的解决方案似乎都不起作用。

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

4

6 回答 6

11

尝试使用:

Application.CalculateUntilAsyncQueriesDone

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

Set r = a.Execute(sqlstr)
    Application.CalculateUntilAsyncQueriesDone
sht.Range("A2").CopyFromRecordset r 
于 2012-10-02T13:31:59.913 回答
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
于 2012-07-12T14:13:51.053 回答
2

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

  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
于 2012-07-12T23:21:42.850 回答
1

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

就像是

Set r = a.Execute(sqlstr)

If Not r.EOF Then
    r.MoveLast
End If

sht.Range("A2").CopyFromRecordset r
于 2012-07-13T02:18:25.823 回答
1

按照 andy holaday 的思路,我通过取消选中外部数据范围属性中的“启用后台刷新”来实现这一点。禁用此功能会强制 excel 在查询运行时等待。

于 2012-09-14T15:03:27.603 回答
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
于 2013-06-24T22:16:34.280 回答