【问题标题】:Recordset does not open in VBA Excel记录集无法在 VBA Excel 中打开
【发布时间】:2017-01-09 22:39:37
【问题描述】:

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

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 things 它运行,可能是因为变量声明,所以也许我应该将查询移动到一个过程?

【问题讨论】:

  • sql 服务器?甲骨文?请用您正在使用的数据库风格标记问题。
  • 如果您在即时窗口中执行debug.print SQL2,然后在 SQL 中运行查询,它运行正常吗?
  • 你的错误号是多少?如果没有运行时错误,则问题出在 SQL 内部,这还不错,但对您的数据库/表无效
  • @shahkalpesh 它的 sql 服务器
  • @GaryEvans 是的,它运行正常,只是在代码中它没有运行

标签: sql-server vba excel


【解决方案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

希望对大家有所帮助

【讨论】:

    【解决方案2】:

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

    第 2 步:写下这段代码,然后按 ENTER 键看看你会得到什么:

    第 3 步:仔细检查结果。尝试将其放入 SQL Server 并查看那里的错误。

    【讨论】:

    • 确实做到了,但它在 SQL Server 中完美运行,没有错误。在 VB.NET 中,就像它不执行 rsAmnts.Open SQL2, CN 行一样,因为我检查了并且即使在执行后记录集仍然关闭
    • 还是什么都没有,正在尝试将其转移到程序中
    • 我将整个查询转移到一个过程中,现在它可以正常工作了,不过感谢您的帮助
    • 您是如何将查询转换为过程的?
    • adCmdStoredProc是指示vba命令查询字符串实际上是一个存储过程名称,命令文本是过程名称
    【解决方案3】:

    这可能不是直接答案,但它不适合 cmets 并可能解决问题。

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

    打开与数据源的连接。

    和

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

    将其分配给Recordset 对象可能会将其公开为记录集。

    而对于Connection.Execute,根据this 将返回一个记录集:-

    返回记录集对象 (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
    

    【讨论】:

    • 我将整个查询转移到一个过程中,现在它工作正常,不过感谢您的帮助
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-22
      • 1970-01-01
      相关资源
      最近更新 更多