sql-server - 从 VBA 执行 SQL Server 存储过程并检索所有消息和结果集
问题描述
我希望能够从 MS Access VBA 执行 SQL Server 存储过程,这样我可以读取 (1) 所有结果集,而不仅仅是第一个;(2) PRINT 语句或类似语句产生的任何消息。
我有一个带有一个输入参数的测试存储过程,它产生 3 个不同的结果集和大约 90 条消息。它调用了几个子存储过程,我可以从 SSMS 很好地执行它,但是(对我来说)不清楚如何最好地从 Access VBA 中执行它。到目前为止,我已经尝试了以下方法:
道。使用 SQL 传递查询,我可以在 DAO 中获得很多我想要的东西,尽管它有点笨拙。它将 3 个结果集中的第一个作为记录集返回,通过使用 LogMessages 属性,我可以获得一个包含发出消息的表(“Admin - NN”)。
ADO。使用 Connection 和 Command 对象,我可以从存储过程中获得表示第一个结果集的单个记录集。但是,我似乎无法说服它只生成一个只向前的记录集。关于消息,在某一时刻,所有消息(至少,我预期的大约 150 条中的前 127 条)都进入了连接的错误集合(!),但是当我将数量减少到大约 90 条时,它们都没有出现在我能找到的任何地方。
正如我一开始所说,我真正想要的是所有结果集的输出以及消息。这可能吗?
这是我当前用于执行存储过程的例程列表:
Function ExecuteStoredProcedureADO(SPName As String, Connect As String, ReturnsRecords As Boolean, _
ParamArray Params() As Variant) As ADODB.Recordset
' v1.0 2018/06/26
' execute stored procedure SPName on a SQL Server database specified by the string in Connect
Dim strErr As String
Dim i As Integer
Dim lngRecsAffected As Long
Dim cnn As ADODB.Connection
Dim cmd As ADODB.Command
Dim errCurr As ADODB.Error
Dim rst As ADODB.Recordset
On Error GoTo Catch
Set ExecuteStoredProcedureADO = Nothing
Set cnn = New ADODB.Connection
cnn.Errors.Clear
cnn.mode = adModeRead
cnn.CommandTimeout = 300
cnn.Open Connect
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandText = SPName
.CommandType = adCmdStoredProc
For i = 0 To UBound(Params) Step 4
.Parameters.Append .CreateParameter(Params(i), Params(i + 1), adParamInput, Params(i + 2), Params(i + 3))
Next i
Set rst = New ADODB.Recordset
rst.CursorType = adOpenStatic
If ReturnsRecords Then
'''Set rst = .Execute(lngRecsAffected)
rst.Open cmd, , adOpenStatic, adLockReadOnly
Else
Set rst = .Execute(, , adExecuteNoRecords)
End If
End With
If ReturnsRecords Then Set ExecuteStoredProcedureADO = rst
Final:
On Error Resume Next
If Len(strErr) > 0 Then Call AppendMsg(strErr)
Set rst = Nothing
Set cmd = Nothing
Exit Function
Catch:
If cnn.Errors.Count > 0 Then
With cnn
For Each errCurr In cnn.Errors
strErr = strErr & "Error " & errCurr.Number & ": " & errCurr.Description _
& " (" & errCurr.Source & ")" & vbCrLf
Next errCurr
strErr = Left(strErr, Len(strErr) - 2) ' truncate final CRLF
End With
Else
strErr = "Error " & Err.Number & ": " & Err.Description & " (" & Err.Source & ")"
End If
MsgBox strErr, vbOKOnly, gtitle
Resume Final
End Function
附录:关于多个结果集,我希望http://msdn.microsoft.com/en-us/library/ms677569%28VS.85%29.aspx 会有所帮助。
解决方案
为了无耻地背负@Erik,您想要创建一个新类来处理您的处理。类似的东西cProcedureHandler
。在此类中,您需要使用关键字声明一个ADODB.Connection
对象:WithEvents
Dim WithEvents cn As ADODB.Connection
然后,您需要编写一个InfoMessage
事件处理程序来处理多个打印语句。有关InfoMessage
事件的信息可以在这里找到,使用连接的Errors
集合可以在这里找到。所以你最终会得到这样的东西:
Private Sub cn_InfoMessage(ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
Dim err As ADODB.Error
Debug.Print cn.Errors.Count & " errors"
For Each err In cn.Errors
' handle each error/message the way you need to.
Debug.Print err.Description
Next err
End Sub
由于您已经处理了处理多条消息的代码,现在您只需要处理多个记录集,您提供的链接中对此进行了很好的解释。我注意到的一件事是示例链接用作rs is nothing
检查何时没有更多记录集,这对我不起作用。我不得不使用 rsState
属性。所以我最终得到了这个:
Public Sub testProcedure()
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim recordSetIndex As Integer
Set cn = modData.getConnection
Set cmd = New ADODB.Command
cmd.ActiveConnection = cn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "dbo.sp_foo"
Set rs = cmd.Execute
recordSetIndex = 1
Do Until rs.State = ObjectStateEnum.adStateClosed
Debug.Print "contents of rs #" & recordIndex
Do Until rs.EOF
Debug.Print rs.Fields(0) & rs.Fields(1)
rs.MoveNext
Loop
Set rs = rs.NextRecordset
recordSetIndex = recordIndex + 1
Loop
cn.Close
Set rs = Nothing
Set cn = Nothing
Set cmd = Nothing
End Sub
然后,当您准备好从 VBA 运行 SP 时,只需执行以下操作:
set obj = new cProcedureHandler
obj.testFooProcedure
另一件事(您可能已经这样做了):确保您在 SQL Server 中的实际存储过程设置了 nocount on。
推荐阅读
- android - Android 双向数据绑定可以与没有样板的 Room 一起使用吗?
- linux - 循环对多个文件执行命令
- asp.net - 为 asp 核心网页获取 HTTP 错误 500.30(开始导航到第一页,下一页会产生此错误)
- javascript - 提交后未发送来自 Stripe 的 TokenKey
- r - R光栅`projectExtent`“不能做这个转换”
- android - android.app.RemoteServiceException:尝试从服务发送通知时 startForeground 的错误通知
- xslt - 计算 xslt 数组中的值
- ssh - 运行包含带有屏幕的 STDIN 重定向的命令
- javascript - 无法控制台记录在另一个项目中有效的 API 响应
- oracle11g - PL/SQL: ORA-00934: 这里不允许使用组函数