使用后期绑定将Recordset对象作为参数传递时,键入Mismatch(13)错误

时间:2018-01-12 02:27:49

标签: excel vba ado recordset late-binding

我正在编写VBA UDF来检索有关编码位置的地理数据。

我有一个Excel工作簿,其中包含共享位置的所有详细信息。

当用户在其工作簿上输入UDF并提供所请求的编码参数时,会发生以下情况:

  1. 他们的工作簿打开与共享驱动器上目标工作簿的ADO连接,并将所有数据查询到记录集中。
  2. 然后将该记录集传递给另一个自定义VBA函数,该函数使用记录集的内容填充VBA字典。
  3. UDF根据用户输入的参数返回字典中的一个值。
  4. (如果现有字典在步骤1之前已经存在于内存中,则会重复使用。)

    在我的计算机上工作正常,但测试它会导致另一台计算机出现明显的引用错误。所以我切换到代码中对象的后期绑定。现在,当我在上面的步骤2中传递记录集时,某些内容会被破坏。我得到了13型不匹配错误。

    这是(部分剪辑的)代码。

    • sSQL是在共享工作簿上执行的查询,在UDF中定义
    • sPath也在UDF中定义
    • vDestination旨在成为工作表(触发PopulateSheetFromRecordset将记录集转储到工作表上以进行可视化)或字典(此处讨论的用例)
    • aColumns是一个数组,它传递有关记录集字段的信息,以确定哪些是键,哪些是值

    我知道问题出在recordset参数上,因为从调用中删除它并且函数声明成功调用了函数,但当然它稍后会失败。

    !!!是用来说明代码失败的地方。

    Public Sub QueryFromExcel(sSQL As String, sPath As String, Optional vDestination As Variant, Optional aColumns As Variant)
    
        'Late Binding
            Dim objMyConn As Object
            Dim objMyRecordset As Object
            Set objMyConn = CreateObject("ADODB.Connection")
            Set objMyRecordset = CreateObject("ADODB.Recordset")
    
        'Open Connection
            On Error GoTo ErrCatch:
            objMyConn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sPath & ";Extended Properties=""Excel 12.0 XML;HDR=Yes,IMEX=1"""
            objMyConn.Open
    
        'Open Recordset
            Set objMyRecordset.ActiveConnection = objMyConn
            objMyConn.CommandTimeout = 0
            objMyRecordset.Open sSQL
            On Error GoTo 0
    
        'Copy Data to Destination    
            If IsMissing(vDestination) Or TypeOf vDestination Is Worksheet Then
                'Add a new sheet if there's no destination
                Dim outSheet As Worksheet
                If IsMissing(vDestination) Then
                    Set outSheet = ActiveWorkbook.Sheets.Add
                Else
                    Set outSheet = vDestination
                End If
                Call PopulateSheetFromRecordset(outSheet, objMyRecordset, aColumns)
            ElseIf TypeOf vDestination Is Dictionary And Not IsMissing(aColumns) Then
    
                '!!! 
                Call PopulateDictionaryFromRecordset(vDestination, objMyRecordset, aColumns)
            End If
    
    End Sub
    

    这是发生错误的定义函数:

    Public Sub PopulateDictionaryFromRecordset(dDictionary As Variant, rsRecords As Recordset, aColumns As Variant)
    

    似乎更改为后期绑定会更改与Recordset对象类型相关的其他内容。研究表明,这可能是因为有多种类型的Recordset对象,但我已将objMyRecordset显式创建为ADODB.Recordset。

1 个答案:

答案 0 :(得分:1)

来自chris neilsen的评论:这是因为当我改为后期绑定时,我的函数定义不再期望Recordset对象。

  

你是后期绑定,因此不能将rsRecords As Recordset。使用rsRecords As Object

更改PopulateDictionaryFromRecordset函数的定义解决了问题:

with aa as (
    select  count(*) count
    from [PRODUCTTAG]
    where ProductID = '19A947C0-6A0F-4A6F-9675-48FBE30A877D'
), bb as
(
    select ProductID, count(*) count
    from [PRODUCTTAG]
    group by ProductID 
)
select distinct b.ProductID
from [dbo].[PRODUCTTAG] a join
    [dbo].[PRODUCTTAG] b on a.TagID = b.TagID cross join
    aa join 
    bb on aa.count = bb.count and b.ProductID = bb.ProductID
where a.ProductID = '19A947C0-6A0F-4A6F-9675-48FBE30A877D'