3

当一个函数从 Access 表中获取一列字段值并将其放入 VBA 集合并返回该集合时,我看到了一种奇怪的情况。该函数将表名和字段名作为参数,并返回包含字段列中所有(或唯一)值的集合。当 sub 运行此函数时,sub 可以读取结果集合中的元素计数。但是,当子尝试访问元素错误结果时。

我说“错误”是因为当我尝试以不同方式访问元素时会得到不同的错误。例如,如果我尝试通过键访问集合元素:

For i=0 to col.count
    Debug.Print col(Cstr(i))        ' results in error: "Automation error"
    i=i+1
Next

我收到“自动化错误”。但是当我尝试通过 For Each 访问集合元素时

For Each var in col 
    Debug.Print var     ' results in  error: "Object invalid or no longer set."
Next

同样奇怪的是,集合的元素可以在将返回它的函数内访问,但不能在集合返回给调用子时访问。但是调用 sub 可以访问集合计数。

使用 Access 表的相同方法可以很好地将一列字段值放入数组中。函数返回一列字段值的数组后,可以将该数组转换为集合。生成的集合可以传递给另一个 sub 并在其中使用。但是该方法不能让函数从 Access 获取信息,将其打包到一个集合中并将包含来自 Access 的信息的集合返回给调用子。

我的代码如下。我已经尝试过,但找不到任何与远程相关的问题。

Option Compare Database
Option Explicit

Sub colUniqueTableValues_tester()
    Dim col As New Collection
    Dim var As Variant
    Dim i As Integer

    Dim strTable As String: strTable = "tbl_Projects"
    Dim strField As String: strField = "Project_Code"

    Set col = colUniqueTableValues(strTable, strField)
    Debug.Print "colListOfUniqueValues_tester: col.count = " + CStr(col.Count)
    ' Set col = colAnyLengthAndStep(4, 1)  ' sub will complete if the collection from Access is overwritten

    i = 0
    For Each var In col
        i = i + 1
        Debug.Print CStr(i) + ": " + col(CStr(i)) ' results in error: "Automation error"
        Debug.Print var ' returns error: "Object invalid or no longer set."
    Next
    Set col = Nothing
End Sub


Function colUniqueTableValues(ByVal strTable As String, ByVal strField As String) As Collection

    Dim strSQL As String
    Dim rs As Recordset
    Dim dbs As Database
    Dim i As Integer
    Dim col As New Collection

    strSQL = "Select distinct " + strField + " from " + strTable
    Set dbs = CurrentDb
    Set rs = dbs.OpenRecordset(strSQL)

    i = 0
    rs.MoveFirst
    Do While Not rs.EOF
        col.Add rs.Fields(strField), CStr(i)
        Debug.Print "Function: " + col(CStr(i)) 'check value
        rs.MoveNext
        i = i + 1
    Loop

    Set colUniqueTableValues = col
    Debug.Print "colUniqueTableValues:  colUniqueTableValues.count = " + CStr(colUniqueTableValues.Count)

    Set dbs = Nothing
    Set rs = Nothing
    Set col = Nothing

End Function


Function colAnyLengthAndStep(ByVal intLength As Integer, ByVal intStep As Integer) As Collection
    Dim col As New Collection
    Dim i As Integer
    Dim var As Variant

    For i = 1 To intLength * intStep Step intStep
        col.Add "Value" + CStr(i), CStr(i)
    Next

    Set colAnyLengthAndStep = col
    Set col = Nothing
End Function
4

1 回答 1

2

第一个问题是由于它rs.Fields(strField)是一个字段对象。在许多情况下,当您对字段进行操作时,您会隐式引用其默认属性,即.Value. 例如,这两个本质上是相同的:

Debug.Print rs.Fields(strField)
Debug.Print rs.Fields(strField).Value

但是,集合的.Add方法不同之处在于它将接受实际对象本身而不是对象的.Value. 要查看实际发生的情况,请在以下位置进行更改colUniqueTableValues()

col.Add rs.Fields(strField), CStr(i)
Debug.Print TypeName(col(CStr(i))) ' <- this says Field2 on my system

您必须显式引用该字段的.Value属性才能将其正确添加到集合中:

col.Add rs.Fields(strField).Value, CStr(i)

更改后,您将在colUniqueTableValues_tester. 当您将项目添加到集合中时,您使用以CStr(i)开头的键为它们提供了密钥i = 0。但是,在从 1 开始的For Each循环中colUniqueTableValues_tester, i。将循环更改为:

For Each var In col
    'i = i + 1
    Debug.Print CStr(i) & ": " & col(CStr(i))
    Debug.Print var
    i = i + 1
Next
于 2013-09-27T04:32:32.500 回答