Pass progress from multi-step ADO query to VBA using Raiserror: Is this possible?
Pass progress from multi-step ADO query to VBA using Raiserror: Is this possible?
前言
我将此问题具体化以符合 SO 询问指南,但如果您愿意,请随时建议进行全面的重新设计。我可能使用了一些不好的做法。
基本问题
我使用 ADO 执行多步骤 SQL 服务器查询,需要几分钟才能执行。我在我的 tsql 查询中使用 Raiserror
来让自己更详细地知道哪些步骤已经完成。是否可以在完成查询之前将这些消息传递给 VBA,同时继续查询?
详细信息和代码
我使用下面的vba来执行下面的t-SQL查询。如您所见,在显示 "Step 1 complete" 和 "Step 2 complete" 的 t-SQL 中出现了两个错误。我能否将这些消息(或交替使用错误编号并将其传递)传递回 VBA,使我能够在继续执行查询的同时检测到它们并更新进度条?
VBA用于执行查询:
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandTimeout = 0
cmd.CommandText = strQuery
Set rst = New ADODB.Recordset
rst.Open cmd
'Go to the second to last recordset of the multi-step query
String1 = Replace(strQuery, ";", "")
For Loop2 = 1 To (Len(strQuery) - (Len(String1) + 1))
Set rst = rst.NextRecordset
Next Loop2
'Copy results
If Not rst.EOF Then
(snip - actions)
Else
MsgBox "Error: No records returned."
End If
精简多步tSQL查询:
--#DRS1: The numbers being researched
select distinct numbers
into #DRS1
from Table1 (nolock)
where numbers in ()
--#DRS1: Index
create nonclustered index Idx_DRS1
on #DRS1(numbers);
Raiserror(“Step 1 complete”,1,1) with nowait;
--#DRS2: Table2 for numbers being researched
select distinct
DRS1.numbers
,a.ID
into #DRS2
from #DRS1 DRS1
join Table2 (nolock) a
on DRS1.numbers = a.numbers
Raiserror(“Step 2 complete”,1,1) with nowait;
--MORE STEPS
(more steps)
(more raiserror statements)
澄清
我不感兴趣:
- 一种在查询完全完成之前不允许我更新进度条的方法。
- 一种使用
Progress
/MaxProgress
的方法,因为据我了解,这会 return 为我的查询中的每个步骤分隔数字,而不是一个进度度量整个查询。
我不太感兴趣:
- 使用
# records affected
消息来确定进度,因为某些步骤可能 return 与之前步骤的记录数相等。
研究
我发现的最接近我正在寻找的东西是 here, but as the discussion of that solution here 说:
This approach would only work for stored procedures that are not intended to return results, say procs that insert data into tables. Another approach would be needed if your stored proc returns a result set.
因为我 return 导致我的查询的最后一步在 Excel 中被操纵,所以我认为这对我不起作用。
外部link代码供参考
SQL:
CREATE PROCEDURE dbo.updTesting As
Declare @RetVal integer
Exec @RetVal = updTesting2
Return @RetVal
GO
CREATE PROCEDURE dbo.updTesting2 As
raiserror('Error From Testing 2 procedure',16,1)
Return -2
GO
VBA:
Private Sub Command1_Click()
On Error GoTo ErrorHandler
Dim db As ADODB.Connection
Dim cmd As ADODB.Command
Set db = New ADODB.Connection
db.CursorLocation = adUseClient
db.Open "provider=sqloledb;data source=handel;initial catalog=northwind;integrated security=sspi"
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = db
.CommandText = "updTesting"
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("@RetVal", adInteger, adParamReturnValue)
.Execute , , adExecuteNoRecords
End With
ExitPoint:
On Error Resume Next
Set cmd.ActiveConnection = Nothing
Set cmd = Nothing
db.Close
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox "Error # " & Err.Number & vbNewLine & vbNewLine & Err.Description
Resume ExitPoint
End Sub
有几种可能性可以解决您的问题:
(1) 捕获查询 运行ning 时出现的错误消息。这是要求的方法。
(2) 将大而长的查询分解成几个较小的块,一个接一个 运行。这样您就知道哪一部分已完成,您可以在将下一个块发送到服务器之前根据该信息更新进度条。
(3) 将大而长的查询更新为 log
它在服务器上的临时 table 进度,然后在另一个查询仍在 运行 时读出此日志宁.
虽然我建议仅在发生错误时才使用错误,而不是 "abuse" 它们用于记录、跟踪或反馈,但两个选项(1 和 2)对于 events
都是非常可行的:
与 Worksheet
事件 Worksheet_Change
、Worksheet_Activate
或 Worksheet_BeforeDoubleClick
类似,ADODB.Connection
和 [=19] 也有 ADODB
事件=].两者都有很好的记录,并且可以通过以下方式在 VBE 中轻松查看:(1) 添加对 Microsoft ActiveX Data Objects x.x Library
的引用 (2) 按 F2
(3) select 在下拉列表中输入 ADODB 库顶部 (4) 的向下菜单,最后在 类 中查找 Recordset
或 Connection
。以下是 Connection
的可用事件:
如您所见,所有事件都标有闪电。要捕获/使用这些事件,您需要在 VBE 中创建一个 Class Module
并向其中添加以下行:
Dim WithEvents adoConnection As ADODB.Connection
之后,您可以使用新创建的 ADODB.Connection
事件和 select 列表顶部所需的事件:
选项 (1) 的适用事件是 InfoMessage event,它发生在“[...] 每当 ConnectionEvent 操作期间出现警告时。”这里的导入部分是 during a connection。因此,只要 ADODB 连接 "gets" 出错,就会自动触发此事件。
当然,这意味着必须发送对服务器的原始查询,而不等待答复。相反,您应该使用上述事件在查询执行时捕获任何错误,并创建另一个事件以在 entire query completed 时自动触发。
有关异步 ADODB 连接及其可能出现的问题的更多帮助,您可能希望在此处查看以下两篇文章:
ExecuteComplete ADODB Connection event not fired with adAsyncExecute parameter
Running multiple async queries with ADODB - callbacks not always firing
如上所述的选项 (3) 和异步 ADODB 连接可以使用类似的方法。
如果这能解决您的问题或者您还有其他问题,请告诉我。
所有可用的 ADODB
活动可在此处查看 https://msdn.microsoft.com/en-us/library/ms675083%28v=vs.85%29.aspx
前言
我将此问题具体化以符合 SO 询问指南,但如果您愿意,请随时建议进行全面的重新设计。我可能使用了一些不好的做法。
基本问题
我使用 ADO 执行多步骤 SQL 服务器查询,需要几分钟才能执行。我在我的 tsql 查询中使用 Raiserror
来让自己更详细地知道哪些步骤已经完成。是否可以在完成查询之前将这些消息传递给 VBA,同时继续查询?
详细信息和代码
我使用下面的vba来执行下面的t-SQL查询。如您所见,在显示 "Step 1 complete" 和 "Step 2 complete" 的 t-SQL 中出现了两个错误。我能否将这些消息(或交替使用错误编号并将其传递)传递回 VBA,使我能够在继续执行查询的同时检测到它们并更新进度条?
VBA用于执行查询:
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandTimeout = 0
cmd.CommandText = strQuery
Set rst = New ADODB.Recordset
rst.Open cmd
'Go to the second to last recordset of the multi-step query
String1 = Replace(strQuery, ";", "")
For Loop2 = 1 To (Len(strQuery) - (Len(String1) + 1))
Set rst = rst.NextRecordset
Next Loop2
'Copy results
If Not rst.EOF Then
(snip - actions)
Else
MsgBox "Error: No records returned."
End If
精简多步tSQL查询:
--#DRS1: The numbers being researched
select distinct numbers
into #DRS1
from Table1 (nolock)
where numbers in ()
--#DRS1: Index
create nonclustered index Idx_DRS1
on #DRS1(numbers);
Raiserror(“Step 1 complete”,1,1) with nowait;
--#DRS2: Table2 for numbers being researched
select distinct
DRS1.numbers
,a.ID
into #DRS2
from #DRS1 DRS1
join Table2 (nolock) a
on DRS1.numbers = a.numbers
Raiserror(“Step 2 complete”,1,1) with nowait;
--MORE STEPS
(more steps)
(more raiserror statements)
澄清
我不感兴趣:
- 一种在查询完全完成之前不允许我更新进度条的方法。
- 一种使用
Progress
/MaxProgress
的方法,因为据我了解,这会 return 为我的查询中的每个步骤分隔数字,而不是一个进度度量整个查询。
我不太感兴趣:
- 使用
# records affected
消息来确定进度,因为某些步骤可能 return 与之前步骤的记录数相等。
研究
我发现的最接近我正在寻找的东西是 here, but as the discussion of that solution here 说:
This approach would only work for stored procedures that are not intended to return results, say procs that insert data into tables. Another approach would be needed if your stored proc returns a result set.
因为我 return 导致我的查询的最后一步在 Excel 中被操纵,所以我认为这对我不起作用。
外部link代码供参考
SQL:
CREATE PROCEDURE dbo.updTesting As
Declare @RetVal integer
Exec @RetVal = updTesting2
Return @RetVal
GO
CREATE PROCEDURE dbo.updTesting2 As
raiserror('Error From Testing 2 procedure',16,1)
Return -2
GO
VBA:
Private Sub Command1_Click()
On Error GoTo ErrorHandler
Dim db As ADODB.Connection
Dim cmd As ADODB.Command
Set db = New ADODB.Connection
db.CursorLocation = adUseClient
db.Open "provider=sqloledb;data source=handel;initial catalog=northwind;integrated security=sspi"
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = db
.CommandText = "updTesting"
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("@RetVal", adInteger, adParamReturnValue)
.Execute , , adExecuteNoRecords
End With
ExitPoint:
On Error Resume Next
Set cmd.ActiveConnection = Nothing
Set cmd = Nothing
db.Close
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox "Error # " & Err.Number & vbNewLine & vbNewLine & Err.Description
Resume ExitPoint
End Sub
有几种可能性可以解决您的问题:
(1) 捕获查询 运行ning 时出现的错误消息。这是要求的方法。
(2) 将大而长的查询分解成几个较小的块,一个接一个 运行。这样您就知道哪一部分已完成,您可以在将下一个块发送到服务器之前根据该信息更新进度条。
(3) 将大而长的查询更新为 log
它在服务器上的临时 table 进度,然后在另一个查询仍在 运行 时读出此日志宁.
虽然我建议仅在发生错误时才使用错误,而不是 "abuse" 它们用于记录、跟踪或反馈,但两个选项(1 和 2)对于 events
都是非常可行的:
与 Worksheet
事件 Worksheet_Change
、Worksheet_Activate
或 Worksheet_BeforeDoubleClick
类似,ADODB.Connection
和 [=19] 也有 ADODB
事件=].两者都有很好的记录,并且可以通过以下方式在 VBE 中轻松查看:(1) 添加对 Microsoft ActiveX Data Objects x.x Library
的引用 (2) 按 F2
(3) select 在下拉列表中输入 ADODB 库顶部 (4) 的向下菜单,最后在 类 中查找 Recordset
或 Connection
。以下是 Connection
的可用事件:
如您所见,所有事件都标有闪电。要捕获/使用这些事件,您需要在 VBE 中创建一个 Class Module
并向其中添加以下行:
Dim WithEvents adoConnection As ADODB.Connection
之后,您可以使用新创建的 ADODB.Connection
事件和 select 列表顶部所需的事件:
选项 (1) 的适用事件是 InfoMessage event,它发生在“[...] 每当 ConnectionEvent 操作期间出现警告时。”这里的导入部分是 during a connection。因此,只要 ADODB 连接 "gets" 出错,就会自动触发此事件。
当然,这意味着必须发送对服务器的原始查询,而不等待答复。相反,您应该使用上述事件在查询执行时捕获任何错误,并创建另一个事件以在 entire query completed 时自动触发。
有关异步 ADODB 连接及其可能出现的问题的更多帮助,您可能希望在此处查看以下两篇文章:
ExecuteComplete ADODB Connection event not fired with adAsyncExecute parameter
Running multiple async queries with ADODB - callbacks not always firing
如上所述的选项 (3) 和异步 ADODB 连接可以使用类似的方法。
如果这能解决您的问题或者您还有其他问题,请告诉我。
所有可用的 ADODB
活动可在此处查看 https://msdn.microsoft.com/en-us/library/ms675083%28v=vs.85%29.aspx