将包含多个值的多行连接成 MS Access 中的单行
Posted
技术标签:
【中文标题】将包含多个值的多行连接成 MS Access 中的单行【英文标题】:Concatenating multiple rows, with multiple values in it, into single line in MS Access 【发布时间】:2019-11-07 21:12:50 【问题描述】:我正在尝试创建简单的需求管理数据库。基本上我有 2 个如下表:
包含 2 列的合同要求:
CR_ReqID | Description
reqCR1 | Contract req description 1
reqCR2 | Contract req description 2
SW_requirements
Title | SW_ReqID | RootReq
SW req description 1| reqSW1 | reqCR1, reqCR2
SW req description 2| reqSW2 | reqCR1
SW req description 3| reqSW3 | reqCR2
我想编写查询来接收这样的表:
CR_ReqID |Description |where used?
reqCR1 |Contract req description 1 |reqSW1, reqSW2
reqCR2 |Contract req description 2 |reqSW1, reqSW3
“合同要求”和“软件要求”表通过“RootReq”列相互关联
我尝试实现 Allen Browne 的代码 http://allenbrowne.com/func-concat.html#Top
这是我的查询
SELECT Contract_requirements.CR_ReqID, ConcatRelated("SW_ReqID ","SW_requirements","RootReq = """ & [CR_ReqID] & """") AS Expr1
FROM Contract_requirements;
但我在 Access 中遇到错误
"Error3831: 多值字段 'RootReq' 不能在 WHERE 或 HAVING 子句中使用"
你们能帮我解决这个问题吗? 提前致谢
【问题讨论】:
只有两个值吗? 所以根据error msg,RootReq是一个多值字段。规范化数据结构会更好。 可以有很多值,而不仅仅是2... 【参考方案1】:构建一个查询,将多值字段元素扩展到单个记录。
查询1
SELECT SW_Requirements.Title, SW_Requirements.SW_ReqID, SW_Requirements.RootReq.Value
FROM SW_Requirements;
然后将该查询用作 ConcatRelated() 函数的源。
SELECT Contract_Requirements.*,
ConcatRelated("SW_ReqID","Query1","[SW_Requirements.RootReq.Value]='" & [CR_ReqID] & "'") AS WhereUsed
FROM Contract_Requirements;
建议不要在命名约定中使用空格或标点符号/特殊字符。
【讨论】:
"Query1" 工作正常,但是当我稍后尝试使用 ConcatRelated() 函数时,我收到错误 3464 标准表达式中的数据类型不匹配。我做错了什么? 很难说。我构建了表来复制您发布的数据,然后构建了非常适合我的查询。关于您的表结构,我需要了解什么?字段都是文本类型吗? 在表 SW_requirements 中,列“RootReq”是数字...当我创建查找规则以在 Contract_Requirements 中提交“CR_ReqID”时,它是由 Access 创建的...我无法将 RootReq 更改为文本... 那么CR_ReqID也必须是数字类型或者Contract_Requirements中还有一个字段是加入RootReq的关键字段。删除分隔 CR_ReqID 的撇号。 我不知道如何检查“SW_Requirements.RootReq.Value”的数据类型是什么...【参考方案2】:您也可以使用我的 DJoin 函数,因为它会接受 SQL 作为源,因此您不需要额外保存的查询:
' Returns the joined (concatenated) values from a field of records having the same key.
' The joined values are stored in a collection which speeds up browsing a query or form
' as all joined values will be retrieved once only from the table or query.
' Null values and zero-length strings are ignored.
'
' If no values are found, Null is returned.
'
' The default separator of the joined values is a space.
' Optionally, any other separator can be specified.
'
' Syntax is held close to that of the native domain functions, DLookup, DCount, etc.
'
' Typical usage in a select query using a table (or query) as source:
'
' Select
' KeyField,
' DJoin("[ValueField]", "[Table]", "[KeyField] = " & [KeyField] & "") As Values
' From
' Table
' Group By
' KeyField
'
' The source can also be an SQL Select string:
'
' Select
' KeyField,
' DJoin("[ValueField]", "Select ValueField From SomeTable Order By SomeField", "[KeyField] = " & [KeyField] & "") As Values
' From
' Table
' Group By
' KeyField
'
' To clear the collection (cache), call DJoin with no arguments:
'
' DJoin
'
' Requires:
' CollectValues
'
' 2019-06-24, Cactus Data ApS, Gustav Brock
'
Public Function DJoin( _
Optional ByVal Expression As String, _
Optional ByVal Domain As String, _
Optional ByVal Criteria As String, _
Optional ByVal Delimiter As String = " ") _
As Variant
' Expected error codes to accept.
Const CannotAddKey As Long = 457
Const CannotReadKey As Long = 5
' SQL.
Const SqlMask As String = "Select 0 From 1 2"
Const SqlLead As String = "Select "
Const SubMask As String = "(0) As T"
Const FilterMask As String = "Where 0"
Static Values As New Collection
Dim Records As DAO.Recordset
Dim Sql As String
Dim SqlSub As String
Dim Filter As String
Dim Result As Variant
On Error GoTo Err_DJoin
If Expression = "" Then
' Erase the collection of keys.
Set Values = Nothing
Result = Null
Else
' Get the values.
' This will fail if the current criteria hasn't been added
' leaving Result empty.
Result = Values.Item(Criteria)
'
If IsEmpty(Result) Then
' The current criteria hasn't been added to the collection.
' Build SQL to lookup values.
If InStr(1, LTrim(Domain), SqlLead, vbTextCompare) = 1 Then
' Domain is an SQL expression.
SqlSub = Replace(SubMask, "0", Domain)
Else
' Domain is a table or query name.
SqlSub = Domain
End If
If Trim(Criteria) <> "" Then
' Build Where clause.
Filter = Replace(FilterMask, "0", Criteria)
End If
' Build final SQL.
Sql = Replace(Replace(Replace(SqlMask, "0", Expression), "1", SqlSub), "2", Filter)
' Look up the values to join.
Set Records = CurrentDb.OpenRecordset(Sql, dbOpenSnapshot)
CollectValues Records, Delimiter, Result
' Add the key and its joined values to the collection.
Values.Add Result, Criteria
End If
End If
' Return the joined values (or Null if none was found).
DJoin = Result
Exit_DJoin:
Exit Function
Err_DJoin:
Select Case Err
Case CannotAddKey
' Key is present, thus cannot be added again.
Resume Next
Case CannotReadKey
' Key is not present, thus cannot be read.
Resume Next
Case Else
' Some other error. Ignore.
Resume Exit_DJoin
End Select
End Function
' To be called from DJoin.
'
' Joins the content of the first field of a recordset to one string
' with a space as delimiter or an optional delimiter, returned by
' reference in parameter Result.
'
' 2019-06-11, Cactus Data ApS, Gustav Brock
'
Private Sub CollectValues( _
ByRef Records As DAO.Recordset, _
ByVal Delimiter As String, _
ByRef Result As Variant)
Dim SubRecords As DAO.Recordset
Dim Value As Variant
If Records.RecordCount > 0 Then
While Not Records.EOF
Value = Records.Fields(0).Value
If Records.Fields(0).IsComplex Then
' Multi-value field (or attachment field).
Set SubRecords = Records.Fields(0).Value
CollectValues SubRecords, Delimiter, Result
ElseIf Nz(Value) = "" Then
' Ignore Null values and zero-length strings.
ElseIf IsEmpty(Result) Then
' First value found.
Result = Value
Else
' Join subsequent values.
Result = Result & Delimiter & Value
End If
Records.MoveNext
Wend
Else
' No records found with the current criteria.
Result = Null
End If
Records.Close
End Sub
完整的文档可以在我的文章中找到:
Join (concat) values from one field from a table or query
如果您没有帐户,请浏览链接:阅读全文。
代码也在 GitHub 上:VBA.DJoin
【讨论】:
谢谢你的帖子,我也试试:)以上是关于将包含多个值的多行连接成 MS Access 中的单行的主要内容,如果未能解决你的问题,请参考以下文章
MS Access - 创建并填充包含由逗号分隔且没有重复值的连接文本的列