我真的不明白这里发生了什么。我正在使用 Excel VBA 连接到 SQL Server Express 数据库并返回 ADO 记录集。我一开始让它工作,但我的代码有点乱,所以我创建了一个新模块并复制了代码,随着我的进行整理。

现在,当我尝试运行 Sub 以返回记录计数时,出现错误“对象关闭时不允许操作”。代码在 MsgBox 行中断。

这是简化的代码:

Dim Server As String
Server = "ServerName"

Dim Database As String
Database = "DatabaseName"

Dim UserID As String
UserID = "UserID"

Dim Pwd As String
Pwd = "Password"

Dim StoredProcedure As String
StoredProcedure = "StoredProcedureName"

Dim conn As New ADODB.Connection
conn.ConnectionString = "Driver={SQL Server};Server=" & Server & "; Database=" & Database & "; UID = " & UserID & "; PWD=" & Pwd & ""
conn.Open

Dim Cmd As New ADODB.Command
Cmd.ActiveConnection = conn
Cmd.CommandText = StoredProcedure
Cmd.CommandType = adCmdStoredProc

Dim params() As String
ReDim Preserve params(4, 2)

params(0, 0) = "Param1"
params(1, 0) = CStr(adInteger)
params(2, 0) = CStr(adParamInput)
params(4, 0) = CStr(6)

params(0, 1) = "Param2"
params(1, 1) = CStr(adInteger)
params(2, 1) = CStr(adParamInput)
params(4, 1) = CStr(6)

params(0, 2) = "Param3"
params(1, 2) = CStr(adInteger)
params(2, 2) = CStr(adParamInput)
params(4, 2) = CStr(15)

Dim sParam4 as String
If Not sParam4 = "" Then
    ReDim Preserve params(4, UBound(params, 2) + 1)
    params(0, UBound(params, 2)) = "Param4"
    params(1, UBound(params, 2)) = CStr(adChar)
    params(2, UBound(params, 2)) = CStr(adParamInput)
    params(3, UBound(params, 2)) = "1"
    params(4, UBound(params, 2)) = sParam4
End If

Dim sParam5 as String
If Not sParam5 = "" Then
    ReDim Preserve params(4, UBound(params, 2) + 1)
    params(0, UBound(params, 2)) = "Param5"
    params(1, UBound(params, 2)) = CStr(adChar)
    params(2, UBound(params, 2)) = CStr(adParamInput)
    params(3, UBound(params, 2)) = Len(sParam5)
    params(4, UBound(params, 2)) = sParam5
End If

Dim Prm As ADODB.Parameter
Set Prm = New ADODB.Parameter
Dim i As Integer
For i = 0 To UBound(params, 2)
    If params(1, i) = CStr(adChar) Then
        Set Prm = Cmd.CreateParameter(params(0, i), CInt(params(1, i)), CInt(params(2, i)), CInt(params(3, i)))
        Cmd.Parameters.Append Prm
        Cmd.Parameters(params(0, i)).Value = params(4, i)
    Else
        Set Prm = Cmd.CreateParameter(params(0, i), CInt(params(1, i)), CInt(params(2, i)))
        Cmd.Parameters.Append Prm
        Cmd.Parameters(params(0, i)).Value = CInt(params(4, i))
    End If
Next i

Dim rs As New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.Open Cmd, , adOpenStatic, adLockOptimistic

MsgBox ("Success! " & rs.RecordCount & " Records Returned!")

当我在 Locals 窗口中查看 rs 变量时,所有属性都被列为显示相同的错误消息。对我来说,似乎记录集正确打开,但随后立即关闭。

奇怪的是,原来的(凌乱的)子现在也不起作用,抛出同样的错误。我不认为我在那里改变了任何东西,只是将它复制到新的 sub 中。

我已经注释掉了旧 sub 所在的整个模块,以防万一发生任何类型的冲突变量情况。这没有任何区别。

我只是看不出它有什么问题!我做了很多研究和阅读,在我未经训练但热情的眼睛看来,一切都很好。

任何帮助将非常感激。

编辑:这是存储过程:
USE [MyDatabase]
GO
/****** Object:  StoredProcedure [dbo].[MyProcedure]    Script Date: 14/09/2015 11:39:00 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[MyProcedure]
    -- Add the parameters for the stored procedure here
    @Param1 int, @Param2 int, @Param3 int, @Param4 char(1), @Param5 varchar(20) = NULL, @Param6 varchar(20) = NULL, @Param7 varchar(20) = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SET ANSI_WARNINGS OFF;

    -- Insert statements for procedure here
    DECLARE @cols AS NVARCHAR(MAX), @query  AS NVARCHAR(MAX)

SET @cols = '';
SELECT @cols = @cols + ',' + QUOTENAME([Field3]) FROM View1
WHERE Field2 = @Param2 AND Field1 = @Param1

SET @cols = STUFF(@cols,1,1,'');


IF @Param5 IS NOT NULL
   SET @query = 'SELECT Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8, Field9, Field10, Field11, Field12, Field13, Field14,' + @cols + ' FROM
(
    SELECT
        Table1.Field1,
        Table1.Field2,
        Table1.Field3,
        Table1.Field4,
        Table1.Field5,
        Table1.Field6,
        Table1.Field7,
        Table1.Field8,
        Table1.Field9,
        Table1.Field10,
        Table1.Field11,
        Table1.Field12,
        Table1.Field13,
        Table1.Field14,
        Table2.Field2,
        Table3.Field1
    FROM Table3
        LEFT OUTER JOIN Table2 ON Table3.Field1 = Table2.Field1
            AND Table3.Field2 = Table2.Field2
        LEFT OUTER JOIN Table4 ON Table3.Field4 = Table4.Field1
            AND Table3.Field2 = Table4.Field3
        RIGHT OUTER JOIN Table1 ON Table2.Field1 = Table1.Field1
            AND Table2.Field2 = Table1.Field15
    WHERE Table1.Field2 = ' + CAST(@Param3 AS char(1)) + '
        AND Table1.Field12 = ''' + @Param5 + '''
        AND Table1.Field15 = ' + CAST(@Param1 AS char(2)) + '
)
AS UP
PIVOT(MAX(Field2) FOR UP.ID IN (' + @cols + ')) AS PVT '
ELSE IF @Param6 IS NOT NULL
   SET @query = 'SELECT Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8, Field9, Field10, Field11, Field12, Field13, Field14,' + @cols + ' FROM
(
    SELECT
        Table1.Field1,
        Table1.Field2,
        Table1.Field3,
        Table1.Field4,
        Table1.Field5,
        Table1.Field6,
        Table1.Field7,
        Table1.Field8,
        Table1.Field9,
        Table1.Field10,
        Table1.Field11,
        Table1.Field12,
        Table1.Field13,
        Table1.Field14,
        Table2.Field2,
        Table3.Field1
    FROM Table3
        LEFT OUTER JOIN Table2 ON Table3.Field1 = Table2.Field1
            AND  Table3.Field2 = Table2.Field2
        LEFT OUTER JOIN Table4 ON Table3.Field4 = Table4.Field1
            AND Table3.Field2 = Table4.Field3
        RIGHT OUTER JOIN Table1 ON Table2.Field1 = Table1.Field1
            AND Table2.Field2 = Table1.Field15
    WHERE Table1.Field2 = ' + CAST(@Param3 AS char(1)) + '
        AND Table1.Field13 = ''' + @Param6 + '''
        AND Table1.Field15 = ' + CAST(@Param1 AS char(2)) + '
)
AS UP
PIVOT(MAX(Field2) FOR UP.ID IN (' + @cols + ')) AS PVT '

ELSE IF @Param7 IS NOT NULL

    SET @query = 'SELECT Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8, Field9, Field10, Field11, Field12, Field13, Field14,' + @cols + ' FROM
(
    SELECT
        Table1.Field1,
        Table1.Field2,
        Table1.Field3,
        Table1.Field4,
        Table1.Field5,
        Table1.Field6,
        Table1.Field7,
        Table1.Field8,
        Table1.Field9,
        Table1.Field10,
        Table1.Field11,
        Table1.Field12,
        Table1.Field13,
        Table1.Field14,
        Table2.Field2,
        Table3.Field1
    FROM Table3
        LEFT OUTER JOIN Table2 ON Table3.Field1 = Table2.Field1
            AND Table3.Field2 = Table2.Field2
        LEFT OUTER JOIN Table4 ON Table3.Field4 = Table4.Field1
            AND Table3.Field2 = Table4.Field3
        RIGHT OUTER JOIN Table1 ON Table2.Field1 = Table1.Field1
            AND Table2.Field2 = Table1.Field15
    WHERE Table1.Field2 = ' + CAST(@Param3 AS char(1)) + '
        AND Table1.Field14 = ''' + @Param7 + '''
        AND Table1.Field15 = ' + CAST(@Param1 AS char(2)) + '
) AS UP

PIVOT(MAX(Field2) FOR UP.ID IN (' + @cols + ')) AS PVT '

ELSE

    SET @query = 'SELECT Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8, Field9, Field10, Field11, Field12, Field13, Field14,' + @cols + ' FROM
(
SELECT
    Table1.Field1,
    Table1.Field2,
    Table1.Field3,
    Table1.Field4,
    Table1.Field5,
    Table1.Field6,
    Table1.Field7,
    Table1.Field8,
    Table1.Field9,
    Table1.Field10,
    Table1.Field11,
    Table1.Field12,
    Table1.Field13,
    Table1.Field14,
    Table2.Field2,
    Table3.Field1
FROM Table3
    LEFT OUTER JOIN Table2 ON Table3.Field1 = Table2.Field1
        AND Table3.Field2 = Table2.Field2
    LEFT OUTER JOIN Table4 ON Table3.Field4 = Table4.Field1
        AND Table3.Field2 = Table4.Field3
    RIGHT OUTER JOIN Table1 ON Table2.Field1 = Table1.Field1
        AND Table2.Field2 = Table1.Field15
WHERE Table1.Field2 = ' + CAST(@Param3 AS char(1)) + '
    AND Table1.Field3 = ''' + @Param4 + '''
    AND Table1.Field15 = ' + CAST(@Param1 AS char(2)) + '
) AS UP

PIVOT(MAX(Field2) FOR UP.ID IN (' + @cols + ')) AS PVT '

EXECUTE (@query)

Set NOCOUNT OFF;
END

我知道参数背后的逻辑不是很......合乎逻辑......但它的工作方式我现在需要它。这是我在工作时会改变的东西。

我还应该说,当我第一次发布问题时,我省略了处理 SP 参数的 VBA 代码部分。我现在刚下类,但回家后我会加进去。我不认为问题出在那里。我基本上处理参数的字符串数组并将它们附加到 Cmd 对象。

编辑:我现在添加了用于创建参数并将它们传递给 Cmd 对象的代码。同样,这有点令人费解,但这是我当时脑子里想出来的,而且确实有效。一旦记录集被填充,我将重新审视逻辑。

最佳答案

请尝试以下代码:

Public Sub AdoTestConnection()
Dim conServer As ADODB.Connection
Dim rstResult As ADODB.Recordset
Dim strDatabase As String
Dim strServer As String
Dim strSQL As String

strServer = "YourServerName"
strDatabase = "YourDatabaseName"

Set conServer = New ADODB.Connection
conServer.ConnectionString = "PROVIDER=SQLOLEDB; " _
    & "DATA SOURCE=" & strServer & "; " _
    & "INITIAL CATALOG=" & strDatabase & "; " _
    & "User ID=" & strLogin & ";" _
    & "Password=" & strPassword
On Error GoTo SQL_ConnectionError
conServer.Open
On Error GoTo 0

Set rstResult = New ADODB.Recordset
strSQL = "set nocount on; "
strSQL = strSQL & "select  1 "
rstResult.ActiveConnection = conServer
On Error GoTo SQL_StatementError
rstResult.Open strSQL
On Error GoTo 0

If Not rstResult.EOF And Not rstResult.BOF Then
    MsgBox "Connection worked. Server returned " & rstResult.Fields(0).Value
Else
    MsgBox "Connection worked. The server did not return any value."
End If

Exit Sub

SQL_ConnectionError:
MsgBox "Problems connecting to the server." & Chr(10) & "Aborting..."
Exit Sub

SQL_StatementError:
MsgBox "Connection established. Yet, there is a problem with the SQL syntax." & Chr(10) & "Aborting..."
Exit Sub

End Sub

如果上述代码有效,那么您可以使用您的过程更改 SQL 命令,如下所示:
strSQL = "set nocount on; "
strSQL = strSQL & "exec StoredProcedureName @Parm1 = " & intValue1 & ", "
strSQL = strSQL & "                         @Parm2 = " & intValue2 & ", "
strSQL = strSQL & "                         @Parm3 = " & intValue3 & ", "
strSQL = strSQL & "                         @Parm4 = N'" & strValue1 & "', "
strSQL = strSQL & "                         @Parm5 = N'" & strValue2 & "', "
strSQL = strSQL & "                         @Parm6 = N'" & strValue3 & "', "
strSQL = strSQL & "                         @Parm7 = N'" & strValue4 & "' "

我强烈支持这种方法而不是您当前的方法,因为它更容易调试。如果您遇到 SQL 语法问题,您可以简单地请求 strSQL 的内容,如下所示:
Debug.Print strSQL

然后您可以将结果复制到 SQL Server Management Studio (SSMS) 并在那里验证结果。
您甚至可能得出结论,您不想使用存储过程并将 SP 的全部内容复制到您的 VBA 代码中。

关于vba - ADO 记录集未在 VBA 中保持打开状态 - "Operation is not allowed when the object is closed",我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32560747/

10-15 14:02