如何将查询中的多值字段传递给VBA函数

时间:2018-06-29 23:59:58

标签: vba ms-access

在我的项目中,我有一个table1,其中有一个ID和一个文本字段。 table2有一个multi-valued field multifield,其中我可以通过搜索从table中选择多个值。

现在,我有query1,我想从multifield中提取值,而不是multifield.value,并将其传递给VBA函数,例如:IDsToNames: table2.multifield。问题是VBA给我这个错误:

The multi-valued field 'table2.multifield` is not valied in the expression IDsToNames(table2.multifield)

现在,我尝试使用IDsToNames([table2].[multifield])获得相同的结果。

这是我查询的SQL:

SELECT table2.Title, table2.multifield, IDstoNames(table2.multifield) AS FieldNames
FROM table2;

如果我从SQL中删除了IDsToNames函数,那么table2.multifield本身将正确返回ID,例如:5, 4, 1。我正在尝试获取table1的第二列,而不是包含ID的第一列。所以我想我会尝试将该字段传递给函数并执行字符串拆分,然后他们在循环中使用dlookup查找它们。但是我无法将字段数据输入到函数中。

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:1)

有没有一种方法可以将多值字段直接从SQL语句传递给VBA函数?不,很遗憾。

但是,可以使用多种替代方法来获取存储在字段中的值列表。在Access多值字段的优缺点上徘徊很容易。我将不做详细说明,但是值得一提的是,多值字段的主要好处是Access接口的方便性和明显的简单性,它能够自动列出并允许选择一对多关系的多个值。试图模仿Access中的行为可能非常笨拙且麻烦(通常是不可能的)。多值字段的许多实现细节都是“隐藏的”(即没有充分记录或没有暴露于标准SQL或VBA编程接口)。这包括将多值字段从SQL语句中传递给VBA函数的功能。不管预期行为看起来多么直观,Access都不会简单地将它显示的相同的串联值列表传递给另一个函数。但是,有时仍然只需要一个简单列表中的值列表即可。信息linked to by Gustav是有用的,在查询多值字段时应该很好理解,但是它仍然不能解决多个值所需的其他完全合理的操作。希望以下指针有用。

  1. 如果标准SQL语句中需要这些值,则建议将主键值传递给VBA函数。然后让VBA函数查找记录并使用DAO记录集检索多值字段值
    • 因为这将调用行的VBA函数,所以这可能(非常)缓慢。可以使用各种技术来优化功能,例如打开静态记录集对象。进一步的细节不在此答案的范围内。
    • 由于此时您已经在编写代码,并且可以根据需要构造VBA和查询,所以最高效的查询将绕过多值字段本身,并使用标准SQL连接来获得所需的内容。例如,如果要获取所有相关的用户名,则打开并枚举以下记录集以建立名称列表:

 sSQL = "SELECT table2.key, table2.multifield.value, UserTable.Username " & _
     " FROM UserTable INNER JOIN table2 ON UserTable.ID = table2.multifield.Value" & _
     " WHERE (table2.key = [KeyParameter])"
 Set qry = CurrentDb.CreateQueryDef(, sSQL)
 qry.Parameters("KeyParameter") = keyPassedToFunction
 Set rs = qry.OpenRecordset

  1. 如果可以/将在代码上下文中将SQL查询作为DAO记录集打开,并且,您仍然需要检索多值字段作为单个字段,是一种枚举VBA中的多值字段的方法。
    • 如果代码最终反复打开和关闭多个记录集,尤其是在多个嵌套循环中,则可能可以通过使用适当的联接重组SQL并更改数据处理顺序来提高效率。
    • Rant:您可能会注意到,尽管Access SQL引擎拒绝将此类对象传递给VBA函数,但SQL语句的基础记录集对象确实确实返回了可以在代码中枚举的对象,这在一定程度上是不一致的。 SQL引擎已经可以将数据装箱和拆箱到VBA变量类型中,因此在实现多值字段时,他们本来可以让SQL引擎简单地将多值记录集对象装箱并将其传递给VBA函数进行处理似乎很合理。类似于下面的代码...因此问题的原始尝试并非没有道理。
    • 下面的代码片段说明了多值字段作为包含DAO.Recordset2对象的DAO.Field对象返回:

Dim rs as Recordset2
Set rs = CurrentDB.OpenRecordset("SELECT table2.multifield ... FROM ...")

Dim sList As String
sList = ""
If TypeOf rs![multifield] Is Recordset2 Then
    Dim rsMVF As Recordset2
    Set rsMVF = rs![multifield]

    Dim bFirst As Boolean
    bFirst = True

    rsMVF.MoveFirst
    Do Until rsMVF.EOF
        If bFirst Then
            sList = rsMVF.Fields(0)
            bFirst = False
        Else
            sList = sList & "," & rs.Fields(0)
        End If
        rsMVF.MoveNext
    Loop
    '* DO NOT CLOSE the Recordset based on the Multivalue field.
    '*   Access will close it automatically.
End If
'* sList will contain comma-separated list of values