从 Access VBA 发送 SQL 查询时停止运行

Posted

技术标签:

【中文标题】从 Access VBA 发送 SQL 查询时停止运行【英文标题】:SQL Query stops running when sent from Access VBA 【发布时间】:2018-10-31 17:18:54 【问题描述】:

我有一个在 SQL Server 14.0 中运行查询的访问 vba 代码。然而,它需要大约 20 分钟才能停止查询并移至我的 vba 代码的下一行。

如果我将代码直接复制到 SQL 中并在那里运行它,它可以正常运行,没有任何问题。我最初认为这是由于连接或命令超时造成的,但通常这应该会生成一条错误消息(即便如此我已将超时设置为 0 以强制它们无限期运行)。

请在下面找到我的代码,它使用 Cursor 循环遍历一系列表以完成相同的任务。此任务涉及循环执行 Do While 直到满足条件。此时循环应该完成并从下一张桌子开始。

它确实完成了 3 个游标循环,但随后开始下一个,然后就停止了。

希望代码有意义,它的访问时间很长,我不得不使用换行符将其全部拆分,以使我的 SQL 字符串更易于破译和(尝试)调试。

''...Declare all relevant variables above...

On Error GoTo 0

SQL_STR1 = "DECLARE @STRSQL AS Varchar(max) " & vbCrLf & _
           "DECLARE @TableName VARCHAR(50) " & vbCrLf & _
           "DECLARE LoopVal CURSOR FOR SELECT TableName_ FROM [DBASE_NAME].[dbo].[a_Base_Year_Matrices] " & vbCrLf & _
           "OPEN LoopVal " & vbCrLf & _
           "FETCH NEXT FROM LoopVal INTO @TableName " & vbCrLf & _
           "WHILE @@FETCH_STATUS = 0 " & vbCrLf & _
           "BEGIN " & vbCrLf & _


SQL_STR2 = "SET @STRSQL = " 

          '...Create Some Tables...

           "WHILE (@COUNTT < 1959 AND @COUNTTER < 150)" & vbCrLf & _
           "BEGIN" & vbCrLf & _

          '...Runs loops to meet conditions, once met drop unneeded tables and create final output...


SQL_STR3 = "EXEC(@STRSQL) " & vbCrLf & _
           "FETCH NEXT FROM LoopVal INTO @TableName " & vbCrLf & _
           "END " & vbCrLf & _
           "CLOSE LoopVal " & vbCrLf & _
           "DEALLOCATE LoopVal "

SQL_ALL = SQL_STR1 + SQL_STR2 + SQL_STR3

Set cnn = New ADODB.Connection
Set rs = New ADODB.Recordset

'Set SQL Server Location
cnn.ConnectionTimeout = 0
cnn.Open "Driver=SQL Server;Server=" & ServerName & ";Trusted_Connection=Yes;"
Set rs.ActiveConnection = cnn

DoCmd.SetWarnings False
cnn.CommandTimeout = 0

''Code to check to paste directly into SQL
''Debug.Print SQL_ALL

rs.Open SQL_ALL, cnn, adOpenForwardOnly

Next b

Next a

End Sub

【问题讨论】:

您是否尝试过使用更现代的驱动程序? SQL Server 是古老的,它是 Windows 98 附带的默认驱动程序。虽然它已经更新了一点,但它不再支持新的开发。你可以下载一个新的here 我们可能需要查看完整的 T-SQL 脚本(顺便说一下,VBA 可以直接从文本文件读取到字符串以避免连接和换行)。此外,考虑对复杂的例程使用存储过程。最后,对于像 SQL 这样的基于集合的声明性语言,游标循环不是推荐的方法。您可能不需要循环或在应用层(即 VBA)运行它们! @ErikvonAsmuth 我必须承认我对司机一无所知。我会下载它并试一试。 @Parfait 我不知道游标,我知道设置它们有点麻烦,但是有技术原因它们不是首选方法吗?现在我已经了解了存储过程,我将尝试一下。我假设它以与我当前代码相同的样式运行,只是这次循环是在 VBA 中? 谢谢@Parfait。下面的答案有效,我将用它来赶上我的最后期限,让客户和 PM 远离我。我将在周末将我们的流程更改为存储过程。感谢您提供格式化代码的帮助,我会先尝试自己设置,我喜欢在获得太多帮助之前先自己尝试。 【参考方案1】:

使用 SET NOCOUNT ON; 语句开始您的 SQL 脚本;

这将抑制所有服务器消息传递并允许结果集进入您正在打开的记录集。

....
SQL_STR1 = "SET NOCOUNT ON; " & vbCrLf & _
           "DECLARE @STRSQL AS Varchar(max) " & vbCrLf & _
           "DECLARE @TableName VARCHAR(50) " & vbCrLf & _
           "DECLARE LoopVal CURSOR FOR SELECT TableName_ FROM [DBASE_NAME].[dbo].[a_Base_Year_Matrices] " & vbCrLf & _
           "OPEN LoopVal " & vbCrLf & _
           "FETCH NEXT FROM LoopVal INTO @TableName " & vbCrLf & _
           "WHILE @@FETCH_STATUS = 0 " & vbCrLf & _
           "BEGIN " & vbCrLf & _
....

SET NOCOUNT ON 在任何 DML 之后抑制“​​xx 行受影响”消息。这是一个结果集,在发送时,客户端(在本例中为您的 ADO 记录集)必须对其进行处理。简而言之,记录集对象不处理这些服务器消息——它需要一个游标来表示基表中的记录、查询结果或以前保存的记录集。当您的记录集返回服务器消息时,它只会给您一个空记录集。我猜你的 VBA 并不期待一个空的记录集,并且当这种情况发生时,你有一些代码块会卡住?很难说没有看到所有的 VBA。

将 NoCount 设置为 ON 会使服务器跳到好东西 - 在这种情况下是查询的结果 - 记录集对象打算处理。

【讨论】:

谢谢你的作品。不太确定我明白为什么。您能否解释关闭“受影响的行数”消息的作用,以及为什么这会使代码继续运行? @Gavin - 我无法将我的 cmets 放在评论中,所以我将它们添加到答案中。希望它有所帮助:-)

以上是关于从 Access VBA 发送 SQL 查询时停止运行的主要内容,如果未能解决你的问题,请参考以下文章

直接和通过 VBA excel 运行相同的存储 Access SQL 查询时获得不同的结果

从 Excel VBA 运行嵌套的 Access SQL 查询

无法从 Excel 中的 VBA 查询连接到 Access 数据库

带有子查询的 SQL 查询上的 MS Access VBA 运行时错误 3075

从 Excel VBA 运行工作参数化 Access SQL 查询 (INSERT INTO) 时出现“需要对象”错误

如何使用sql语句和vba将数据从MS-Access导入excel power查询?