excel vba:暂停参数化SQL查询完成?

时间:2011-02-24 15:10:52

标签: excel vba excel-vba parameterized-query

我有一个工作簿,其中我的几个数据源将参数传递回SQL查询,具体取决于某些下拉菜单/用户操作。这样可以保持工作簿的修剪,改进计算等 - 在工作簿中本地保留所有项目级别的详细信息是不切实际的。

我的VBA的某些元素依赖于对来自这些参数化查询的数据的评估。这里出现了问题 - 在评估宏中的所有内容之前,VBA不会等待参数传递回查询。

我很好奇是否有任何想法或建议有关以编程方式“暂停”VBA执行的最佳实践,直到Feed刷新为止。我现在的工作是将我的VBA分成两部分,将依赖于已更改数据的任何内容抛出到单独的函数中,并使用application.ontime暂停X秒。

Application.OnTime Now + TimeSerial(0, 0, 10), "Restart"

这是一个90%的解决方案,但它不太理想。时间长度是任意的 - 在非常慢的连接上它不够长,而在快速连接上则不必要地慢。

理想情况下,会有某种方式等待Excel准备就绪然后继续。与使用MS Internet Controls库时的方式类似,您可以使用

Do Until .document.ReadyState = "complete"

暂停执行,直到IE返回就绪状态。任何更优雅的解决方案策略?

每个jon下面的

编辑,添加代码并解释SQL查询的工作原理:

select sts1.studentid, sts1.alphascore as testcycle, 
sts2.numscore as lexile, sts3.alphascore as gleq, sts4.numscore as nce

from ps.studenttestscore sts1
join ps.students stu on (sts1.studentid = stu.id)
join ps.studenttestscore sts2 on (sts1.studenttestid = sts2.studenttestid)
join ps.studenttestscore sts3 on (sts1.studenttestid = sts3.studenttestid)
join ps.studenttestscore sts4 on (sts1.studenttestid = sts4.studenttestid)

where (stu.id = ? ) and (sts1.testscoreid = 578) and (sts2.testscoreid = 575) 
and (sts3.testscoreid = 577) and (sts4.testscoreid = 576)

?是传递相关学生ID的参数 - MS查询使用该参数的单元格值。它看起来只是根据选择的学生进行查找的单元格:

=IFERROR(INDEX(Stu!$B:$F,MATCH(Student!B2,Stu!$F:$F,0),1),999999)

(如果以某种方式选择了不正确的值,iferror只会传递任意数字,以防止出现令人讨厌的对话框)。

1 个答案:

答案 0 :(得分:2)

您的错误是使用MS-Query。使用ADODB对数据库调用进行编码,并等待ADODB.Command对象的Execute方法。

......如果这就是你真正在做的事情。这里有一定程度的猜测,但看起来好像查询的状态 - 而不是它嵌入的表格 - 是你需要的信息。

这段代码异步调用一个SQL查询 - 它在概念上类似于一个命令对象,这是(我认为)你实际在做什么 - 原始的'sleep'循环可以用进度条代替,或代码为其他地方的投票标志和计算。

仅供参考,ADO对象的状态和状态属性可能会令人困惑。通常,零表示关闭,1表示打开(对于返回打开的连接或数据集的对象),高于1的值对应于等待或执行。

当然,您可以同步调用查询。

我可以为你提供'DataConnection'的代码,但是你最好去ConnectionStrings.com。


Public Function FetchRecordSet(SQL As String, Optional CursorType As CursorTypeEnum = adOpenForwardOnly) As ADODB.Recordset
On Error Resume Next

Set FetchRecordSet = New ADODB.Recordset

With FetchRecordSet

    .CacheSize = 8
    Set .ActiveConnection = DataConnection
    .Open SQL, , CursorType, adLockReadOnly, adCmdText + adAsyncFetch

    Do While .State > 1
        Application.StatusBar = "Retrieving data... " 
        Sleep 250
    Loop

End With

Application.StatusBar = False

End Function





[更新]

自从我发布这个答案后,我学会了一些东西:

如果您知道命令的名称,行集返回函数或MS-Access数据库中的命名查询,请不要这样打扰它:


    SQL = "SELECT * FROM MyQuery"
    .Open SQL, , CursorType, adLockReadOnly, adCmdText + adAsyncFetch

按名称调用命令,并使用adCmdStoredProc常量告诉数据库引擎它是命名命令:


    SQL = "MyQuery"
    .Open SQL, , CursorType, adLockReadOnly, adCmdStoredProc + adAsyncFetch

它运行得更快,更快。

在MSDN上查找CommandTypeEnum,并使用最适合您的方法:

https://msdn.microsoft.com/en-us/library/ms675946(v=vs.85).aspx

对命名表使用adCmdTable,看看对于'view'对象是否比adCmdStoredProc效果更好 - 我发现它在数据库引擎之间有所不同。

[/更新]