I have an Access 2010 database with a relationship between parent and child tables. I would like to be able to query the database from an external application and show values from the child table as a concatenated list of values in a single column, similar to what MySQL can produce with its GROUP_CONCAT()
function.
This has been asked here many times before, e.g., here:
Combine values from related rows into a single concatenated string value
but those solutions rely on a custom VBA function that is not available to external queries.
Is there a way to make such a concatenated list available to external queries without having to manually build the list in the other application?
Issue
Historically, the Access solution for a
GROUP_CONCAT()
-type query has been to use a VBA function like Allen Browne'sConcatRelated()
(ref: here). However, custom VBA functions are only available to queries run from within Microsoft Access itself, so this is not a viable solution for queries against an Access database from some other application (e.g., a .NET application using OLEDB or ODBC).Solution
With an Access 2010 (or newer) database we can emulate the behaviour of a MySQL
GROUP_CONCAT()
query by adding a Long Text ("Memo") field to the parent table and using data macros on the child table to maintain the concatenated list.For example, for tables [Parents] ...
... and [Children] ...
... we can add a new
Memo
/Long Text
field named [ChildList] to the [Parents] table and then add the following data macros to the [Children] table:[Named Macro: UpdateChildList]
[After Insert]
[After Update]
[After Delete]
Results
As changes are made to the child table the list in the parent table will automatically be updated:
Notes
The [ChildList] field is for display purposes only. Editing the values in that field will not change the values in the child table.
The list is separated with
";" & Chr(160)
to differentiate it from any";" & Chr(32)
pairs that may be in the actual data. If the non-breaking space (Chr(160)
) characters mess up wrapping of the list then we could use theReplace()
function in our query to convert";" & Chr(160)
to";" & Chr(32)
or"," & Chr(32)
or whatever would be most appropriate.To populate the lists with existing child data we simply need to "update" one child record for each parent, like so