【问题标题】:Run SQL Server stored procedure from VBA从 VBA 运行 SQL Server 存储过程
【发布时间】:2020-02-24 03:23:15
【问题描述】:

这是我在 SQL Server Management Studio 中运行良好的存储过程。

exec GroupCommissions @GroupNumberEntry = '01142' 

应该生成一个数据表。

我正在尝试使用以下代码在 vba 中运行它:

 Dim rs As ADODB.Recordset
    Dim cnSQL As ADODB.Connection
    Dim sqlcommand As ADODB.Command, prm As Object

    Set cnSQL = New ADODB.Connection
    cnSQL.Open "Provider=SQLOLEDB; Data Source=bddc1didw1;Initial Catalog=Actuarial; Trusted_connection=Yes; Integrated Security='SSPI'"

    Set sqlcommand = New ADODB.Command
    sqlcommand.ActiveConnection = cnSQL

    sqlcommand.CommandType = adCmdStoredProc
    sqlcommand.CommandText = "GroupCommissions"
    Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adParamInput)
    sqlcommand.Parameters.Append prm
    sqlcommand.Parameters("GroupNumberEntry").Value = "01142"

    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.LockType = adLockOptimistic
    rs.Open sqlcommand

    ActiveSheet.Range("a3").CopyFromRecordset rs

但它只是返回空白,我无法弄清楚我做错了什么。还有更简单的方法吗?

正如下面所讨论的,我已通过将 SET NOCOUNT ON 添加到原始存储过程来解决此问题。我现在的问题是我想在相同的代码中执行第二个存储过程,但它似乎只适用于一个。但是,它们都单独工作。所以要么我必须重新打开连接,要么在定义的变量上使用 2?代码如下:

Dim rs As ADODB.Recordset

    Dim cnSQL As ADODB.Connection
    Dim sqlcommand As ADODB.Command, prm As Object, prm2 As Object

    Set cnSQL = New ADODB.Connection
    cnSQL.Open "Provider=SQLOLEDB; Data Source=bddc1didw1;Initial Catalog=Actuarial; Trusted_connection=Yes; Integrated Security='SSPI'"

    Set sqlcommand = New ADODB.Command


    sqlcommand.ActiveConnection = cnSQL


'groupdates

    sqlcommand.CommandType = adCmdStoredProc
    sqlcommand.CommandText = "GroupDate"
    Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, adParamInput, 5)
    Set prm2 = sqlcommand.CreateParameter("ValuationDateEntry", adDate, adParamInput)
    sqlcommand.Parameters.Append prm
    sqlcommand.Parameters.Append prm2

    sqlcommand.Parameters("GroupNumberEntry").Value = "01132"
    sqlcommand.Parameters("ValuationDateEntry").Value = "08-31-2019"


    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.LockType = adLockOptimistic
    rs.Open sqlcommand

    ActiveSheet.Range("a2").CopyFromRecordset rs



    'GroupCommissions


    sqlcommand.CommandType = adCmdStoredProc
    sqlcommand.CommandText = "GroupCommissions"
    Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, adParamInput, 5)

    sqlcommand.Parameters.Append prm
    sqlcommand.Parameters("GroupNumberEntry").Value = "01132"

    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.LockType = adLockOptimistic
    rs.Open sqlcommand

    ActiveSheet.Range("DB2").CopyFromRecordset rs

【问题讨论】:

    标签: sql-server vba stored-procedures


    【解决方案1】:

    您可以尝试直接将 SQL PROCEDURE 作为 CALL 函数发送。 看看这个:

    Public connDB As New ADODB.Connection
    Public rs As New ADODB.Recordset
    Public strSQL As String
    Public strConnectionstring As String
    Public strServer As String
    Public strDBase As String
    Public strUser As String
    Public strPwd As String
    Public PayrollDate As String
    
    Sub WriteStoredProcedure()
         PayrollDate = "2017/05/25"
         Call ConnectDatabase
         On Error GoTo errSP
         strSQL = "EXEC spAgeRange '" & PayrollDate & "'"
         connDB.Execute (strSQL)
         Exit Sub
    errSP:
    MsgBox Err.Description
    End Sub
    
    Sub ConnectDatabase()
         If connDB.State = 1 Then connDB.Close
         On Error GoTo ErrConnect
         strServer = "SERVERNAME" ‘The name or IP Address of the SQL Server
         strDBase = "TestDB"
         strUser = "" 'leave this blank for Windows authentication
         strPwd = ""
    
         If strPwd > "" Then
             strConnectionstring = "DRIVER={SQL Server};Server=" & strServer & ";Database=" & strDBase & ";Uid=" & strUser & ";Pwd=" & strPwd & ";Connection Timeout=30;"
         Else
             strConnectionstring = "DRIVER={SQL Server};SERVER=" & strServer & ";Trusted_Connection=yes;DATABASE=" &    strDBase 'Windows authentication
         End If
         connDB.ConnectionTimeout = 30
         connDB.Open strConnectionstring
    Exit Sub
    ErrConnect:
         MsgBox Err.Description
    End Sub
    

    【讨论】:

    • 这根本不是处理这个问题的好方法。当 OP 尝试使用正确的参数化查询时,您的代码对 sql 注入开放。此外,由于您没有正确处理连接,当有多个用户时,这将导致连接池大量减少。
    【解决方案2】:

    尝试用以下内容替换该行:

    Set prm = sqlcommand.CreateParameter("GroupNumberEntry", adVarChar, GroupNumberEntry, 255)

    根据 proc 的定义设置字段类型和长度。

    您的代码对我来说看起来不错,所以我将它复制到 Excel(2016...)中并尝试了它。它在该行上给了我一个错误,但将附加参数值添加到 CreateParameter 解决了这个问题。 耸耸肩 没关系,因为这些是可选参数,除非提供者级别可能存在某些问题。

    【讨论】:

    • 它仍然给我一个空白。真的卡在这里了!
    • 如果您在代码示例的最后一行放置断点并检查rs,它是否有行?
    • PRM 低于值的手表是空白的。我知道我的连接可以正常工作,因为最初我在 VBA 代码中使用了我的 SQL 并且可以正常工作,但是它很混乱而且很长,所以我将它全部放入一个存储过程中,我也已经对其进行了测试和工作。
    • 是否有另一种方法来执行此代码:exec GroupCommissions @GroupNumberEntry = '01142' 然后从记录集中粘贴?
    • 不,这是正确的做法。你可以试试dim prm as ADODB.Parameter 看看它是否被绊倒了。不过,我不认为是这样。您可以发布其余的 VBA 程序吗?
    猜你喜欢
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 2018-11-10
    • 1970-01-01
    • 2011-11-07
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多