Recordset无法在VBA Excel中打开

时间:2017-01-05 11:04:51

标签: sql-server excel vba excel-vba

我的Excel VBA记录集有问题,它运行所有其他查询,但是在SQL Server中运行的这一个特定查询不能使用Recordset打开。 这是代码块:

SQL2 = "DECLARE @val VARCHAR (2000) " & vbCrLf & "DECLARE @cert VARCHAR(2000) " & vbCrLf & _
    "DECLARE @inv VARCHAR(2000) " & vbCrLf & "DECLARE @loc INT " & vbCrLf & _
    "DECLARE @res TABLE(val VARCHAR(100)) " & vbCrLf & _
    "DECLARE @Delimiter VARCHAR(2) " & vbCrLf & "SET @val = '' " & vbCrLf & _
    "SET @Delimiter = ',' " & vbCrLf & "SELECT @cert = " & vbCrLf & "CASE WHEN @cert = '' " & vbCrLf & _
    "THEN CertInvsRec " & vbCrLf & "ELSE @cert + coalesce(',' + CertInvsRec, '') " & vbCrLf & _
    "End " & vbCrLf & "FROM  ProjValuations WHERE (Proj = 'TPL-15-020') " & vbCrLf & _
    "SELECT @inv = " & vbCrLf & "CASE WHEN @inv = '' " & vbCrLf & "THEN InvsAmountRec " & vbCrLf & _
    "ELSE @inv + coalesce(',' + InvsAmountRec, '') " & vbCrLf & "End " & vbCrLf & _
    "FROM  ProjValuations WHERE (Proj = 'TPL-15-020') " & vbCrLf & "SET @val = CONCAT(@inv, ',', @cert) " & vbCrLf & _
    "IF NOT  @val = ',' " & vbCrLf & "DECLARE @Index SMALLINT, @Start SMALLINT, @DelSize SMALLINT " & vbCrLf & _
    "SET @DelSize = LEN(@Delimiter) " & vbCrLf & "WHILE LEN(@val) > 0 " & vbCrLf & "BEGIN " & vbCrLf & _
    "SET @Index = CHARINDEX(@Delimiter, @val) " & vbCrLf & "IF @Index = 0 " & vbCrLf & "BEGIN " & vbCrLf & _
    "INSERT INTO @res(val) VALUES(LTRIM(RTRIM(@val))) " & vbCrLf & "BREAK " & vbCrLf & _
    "End " & vbCrLf & "Else " & vbCrLf & "BEGIN " & vbCrLf & _
    "INSERT INTO @res (val) VALUES (LTRIM(RTRIM(SUBSTRING(@val, 1,@Index - 1)))) " & vbCrLf & _
    "SET @Start = @Index + @DelSize " & vbCrLf & _
    "SET @val = SUBSTRING(@val, @Start , LEN(@val) - @Start + 1) " & vbCrLf & "End " & vbCrLf & _
    "End " & vbCrLf & vbCrLf & "SELECT " & vbCrLf & "( " & vbCrLf & _
    "SELECT sum(InvTotExcl) FROM invnum WHERE autoindex in ( " & vbCrLf & _
    "SELECT iInvoiceID FROM _bvSalesOrdersFull WHERE (ProjectCode LIKE '%020%') AND " & vbCrLf & _
    "(StatusDescription = 'CERTIFICATE') and iInvoiceID not in (SELECT * FROM @res)) " & vbCrLf & _
    ") " & vbCrLf & " AS certAmnt, " & vbCrLf & "( " & vbCrLf & _
    "SELECT SUM(InvTotExcl) FROM _bvSalesOrdersFull WHERE (ProjectCode = 'TPL-15-020') AND " & vbCrLf & _
    "(StatusDescription = 'STANDARD') and iInvoiceID not in (SELECT * FROM @res) " & vbCrLf & ") AS invAmnt" 
If rsAmnts.State = adStateOpen Then rsAmnts.Close 
rsAmnts.Open SQL2, CN, adOpenStatic, adLockReadOnly

任何帮助都将受到高度赞赏,提前谢谢。

如果有帮助,如果我使用直接SELECT查询,例如它运行的 SELECT * FROM ,可能是因为变量声明,所以我应该将查询移到一个过程?

4 个答案:

答案 0 :(得分:1)

因此,我发现有效的解决方案是通过SQL查询创建一个过程

/****** Object:  StoredProcedure [dbo].[valuationReports]    Script Date: 1/9/2017 17:24:26 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE PROCEDURE [dbo].[valuationReports] 
    @proj AS VARCHAR(200)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @val VARCHAR (2000)
    DECLARE @cert VARCHAR(2000)
    DECLARE @inv VARCHAR(2000)
    DECLARE @loc INT
    DECLARE @res TABLE(val VARCHAR(100))
    DECLARE @Delimiter VARCHAR(2)
    SET @val = ''
    SET @Delimiter = ','
    SELECT @cert = coalesce(',' + CertInvsRec, '')
        FROM  ProjValuations WHERE (Proj = @proj)
    SELECT @inv = coalesce(',' + InvsAmountRec, '')
        FROM  ProjValuations WHERE (Proj = @proj)
    SET @val = CONCAT(@inv, ',', @cert)
    --select @val as 'tst'
    IF NOT  @val = ','
    BEGIN
        DECLARE @Index SMALLINT, @Start SMALLINT, @DelSize SMALLINT
        SET @DelSize = LEN(@Delimiter)
        WHILE LEN(@val) > 0
        BEGIN
            SET @Index = CHARINDEX(@Delimiter, @val)
            IF @Index = 0
                BEGIN
                    INSERT INTO @res(val) VALUES(LTRIM(RTRIM(@val)))
                    BREAK
                END
            ELSE
                BEGIN
                    INSERT INTO @res (val) VALUES (LTRIM(RTRIM(SUBSTRING(@val, 1,@Index - 1))))
                    SET @Start = @Index + @DelSize
                    SET @val = SUBSTRING(@val, @Start , LEN(@val) - @Start + 1)
                END
        END
    END
    SET @cert = ''
    SET @inv = ''
    SELECT @cert = 
        CASE WHEN @cert = ''
        THEN cast(iInvoiceID as varchar)
        ELSE @cert + coalesce(',' + cast(iInvoiceID as varchar), '')
        END
        FROM _bvSalesOrdersFull WHERE (ProjectCode = @proj) AND 
        (StatusDescription = 'CERTIFICATE') AND iInvoiceID NOT IN (SELECT * FROM @res)
    SELECT @inv = 
        CASE WHEN @inv = ''
        THEN cast(iInvoiceID as varchar)
        ELSE @inv + coalesce(',' + cast(iInvoiceID as varchar), '')
        END
        FROM  _bvSalesOrdersFull WHERE (ProjectCode = @proj) AND 
        (StatusDescription = 'STANDARD') AND iInvoiceID NOT IN (SELECT * FROM @res)

    SELECT 
    (
        SELECT ISNULL(SUM(InvTotExcl), 0) FROM invnum WHERE autoindex in (
        SELECT iInvoiceID FROM _bvSalesOrdersFull WHERE (ProjectCode = @proj) AND 
        (StatusDescription = 'CERTIFICATE') AND iInvoiceID NOT IN (SELECT * FROM @res)
        )
    ) AS 'cert',
    (
        SELECT ISNULL(SUM(InvTotExcl), 0) FROM _bvSalesOrdersFull WHERE (ProjectCode = @proj) AND 
        (StatusDescription = 'STANDARD') AND iInvoiceID NOT IN (SELECT * FROM @res)
    ) AS 'inv',
    (
        SELECT ISNULL(@cert, '')
    ) AS 'certIn',
    (
        SELECT ISNULL(@inv, '')
    ) AS 'invIn'

END

GO

我使用的VBA代码是

'Declare variables
Dim CN As Connection
Dim cmd As Command, rsAmnts As Recordset

'Initialise the variables
Set CN = New Connection
Set cmd = New Command

'Open connection
CN.Open ("connection string")

'Call procedure assigning the variable
cmd.ActiveConnection = CN
cmd.CommandText = "valuationReports"
cmd.CommandType = adCmdStoredProc
cmd.Parameters.Refresh

'The variable assigned a value
cmd(1) = "TP-15-0020"

'Set Recordset by executing the command i.e. procedure
Set rsAmnts = cmd.Execute

希望这可以帮助那里的任何人

答案 1 :(得分:0)

步骤1:打开即时窗口,粘贴您的代码,然后在每一行按Enter键:

enter image description here

步骤2:当你按下ENTER时,写下这个并看看你得到了什么:

enter image description here

步骤3:仔细检查结果。尝试将其带入SQL Server并在那里查看错误。

答案 2 :(得分:0)

这可能不是直接的答案,但它不符合评论并可能解决问题。

您正在使用Connection.Open根据this可能无法立即为您提供记录集: -

  

打开与数据源的连接。

  

在客户端Connection对象上使用时,Open方法实际上并未建立与服务器的连接,直到在Connection对象上打开Recordset为止。

可能是将它分配给Recordset对象的情况会将其公开为记录集。

而使用Connection.Execute,根据this将返回记录集: -

  

返回Recordset对象(ADO)对象引用。

  

执行指定的查询,SQL语句,存储过程或特定于提供程序的文本。

我从中读到的是Connection.Open将打开一个连接,这可能不是执行特定命令的情况,而只是打开对数据的访问。 Connection.Execute明确提到运行查询和命令,因此可以接受您的声明以及标准查询。

执行的快速示例: -

Public Sub Sample(ByVal SQL2 As String)
Dim DBConn  As ADODB.Connection
Dim RS      As ADODB.Recordset

Set DBConn = New ADODB.Connection
    DBConn.Open "Provider=SQLOLEDB;Server=[SERVER];Database=[DATABASE];User Id=[USER];Password=[PASSWORD;"
    Set RS = DBConn.Execute(SQL2)
        'RS is a recordset at this point
        RS.Close
    Set RS = Nothing
    DBConn.Close
Set DBConn = Nothing

End Sub

答案 3 :(得分:0)

确保检查区域设置,这将影响数据输入数据库的方式