使用后期绑定将 Recordset 对象作为参数传递时出现类型不匹配 (13) 错误
Type Mismatch (13) error when passing Recordset object as parameter using late binding
我正在编写 VBA UDF 来检索有关编码位置的地理数据。
我有一个 Excel 工作簿,其中包含共享位置中的所有详细信息。
当用户在他们的工作簿上输入 UDF 并提供请求的编码参数时,会发生以下情况:
- 他们的工作簿打开到共享驱动器上目标工作簿的 ADO 连接,并将所有数据查询到记录集中。
- 然后将该记录集传递给另一个自定义 VBA 函数,该函数用记录集的内容填充 VBA 字典。
- UDF returns根据用户输入的参数在字典中的值之一。
(如果在步骤 1 之前已经存在于内存中,则重复使用现有词典。)
这个 在我的电脑上工作得很好,但在另一台电脑上测试它会导致明显的引用错误。所以我为代码中的对象切换到 late binding。现在,当我在上面的第 2 步中传递记录集时,出现了问题。我收到类型 13 不匹配错误。
这是(部分截取的)代码。
- sSQL 是在共享工作簿上执行的查询,在 UDF 中定义
- sPath也在UDF中定义
- vDestination 旨在成为一个 Worksheet(触发 PopulateSheetFromRecordset 将记录集转储到 sheet 以进行可视化)或一个 Dictionary(此处讨论的用例)
- aColumns 是一个数组,它传递有关记录集字段的信息以确定哪些是键,哪些是值
我知道问题出在记录集参数上,因为将其从调用中删除并且函数声明成功调用了该函数,但当然后来失败了。
这个!!!那里是为了说明代码在哪里失败。
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.
来自 chris neilsen 的评论:这是因为当我更改为后期绑定时,我的函数定义不再需要 Recordset 对象。
You are late binding, so can't have rsRecords As Recordset. Use rsRecords As Object
更改 PopulateDictionaryFromRecordset 函数的定义解决了问题:
Public Sub PopulateDictionaryFromRecordset(dDictionary As Variant, rsRecords As **Object**, aColumns As Variant)
我正在编写 VBA UDF 来检索有关编码位置的地理数据。
我有一个 Excel 工作簿,其中包含共享位置中的所有详细信息。
当用户在他们的工作簿上输入 UDF 并提供请求的编码参数时,会发生以下情况:
- 他们的工作簿打开到共享驱动器上目标工作簿的 ADO 连接,并将所有数据查询到记录集中。
- 然后将该记录集传递给另一个自定义 VBA 函数,该函数用记录集的内容填充 VBA 字典。
- UDF returns根据用户输入的参数在字典中的值之一。
(如果在步骤 1 之前已经存在于内存中,则重复使用现有词典。)
这个 在我的电脑上工作得很好,但在另一台电脑上测试它会导致明显的引用错误。所以我为代码中的对象切换到 late binding。现在,当我在上面的第 2 步中传递记录集时,出现了问题。我收到类型 13 不匹配错误。
这是(部分截取的)代码。
- sSQL 是在共享工作簿上执行的查询,在 UDF 中定义
- sPath也在UDF中定义
- vDestination 旨在成为一个 Worksheet(触发 PopulateSheetFromRecordset 将记录集转储到 sheet 以进行可视化)或一个 Dictionary(此处讨论的用例)
- aColumns 是一个数组,它传递有关记录集字段的信息以确定哪些是键,哪些是值
我知道问题出在记录集参数上,因为将其从调用中删除并且函数声明成功调用了该函数,但当然后来失败了。
这个!!!那里是为了说明代码在哪里失败。
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.
来自 chris neilsen 的评论:这是因为当我更改为后期绑定时,我的函数定义不再需要 Recordset 对象。
You are late binding, so can't have rsRecords As Recordset. Use rsRecords As Object
更改 PopulateDictionaryFromRecordset 函数的定义解决了问题:
Public Sub PopulateDictionaryFromRecordset(dDictionary As Variant, rsRecords As **Object**, aColumns As Variant)