在不使用VBA的情况下,从Access数据库创建子表值的连接列表

时间:2015-05-06 12:20:59

标签: ms-access-2010 ms-access-2013

我有一个Access 2010数据库,其中包含父表和子表之间的关系。我希望能够从外部应用程序查询数据库,并将子表中的值显示为单个列中的值的连接列表,类似于MySQL可以使用其GROUP_CONCAT()函数生成的值。

之前已经多次询问过这个问题,例如:

Combine values from related rows into a single concatenated string value

但这些解决方案依赖于外部查询无法使用的自定义VBA功能。

有没有办法让这种连接列表可用于外部查询而无需在其他应用程序中手动构建列表?

1 个答案:

答案 0 :(得分:1)

问题

历史上,GROUP_CONCAT()类型查询的Access解决方案一直使用像Allen Browne的ConcatRelated()(参考:here)这样的VBA函数。但是,自定义VBA功能仅适用于从Microsoft Access本身运行的查询,因此对于从某些其他应用程序(例如,使用OLEDB或ODBC的.NET应用程序)查询Access数据库,这不是一个可行的解决方案。

解决方案

使用Access 2010(或更新版本)数据库,我们可以通过向父表添加长文本(" Memo")字段并使用{{{}来查询MySQL GROUP_CONCAT()查询的行为3)}在子表上维护连接列表。

例如,对于表格[Parents] ...

ParentID  ParentName   
--------  -------------
       1  Homer Simpson
       2  Ned Flanders 

......和[儿童] ......

ChildID  ParentID  ChildName          DisplayOrder
-------  --------  -----------------  ------------
      1         1  Lisa                          2
      2         1  Bart                          1
      3         2  Rod, the elder                1
      4         1  Maggie                        3
      5         2  Todd, the younger             2

...我们可以将一个名为[ChildList]的新Memo / Long Text字段添加到[Parents]表中,然后将以下数据宏添加到[Children]表中:

[命名宏:UpdateChildList]

UpdateChildList.png

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application">
    <DataMacro Name="UpdateChildList">
        <Parameters>
            <Parameter Name="prmParentID"/>
        </Parameters>
        <Statements>
            <Action Collapsed="true" Name="SetLocalVar">
                <Argument Name="Name">newList</Argument>
                <Argument Name="Value">Null</Argument>
            </Action>
            <ForEachRecord>
                <Data Alias="c">
                    <Query>
                        <References>
                            <Reference Source="Children" Alias="c"/>
                        </References>
                        <Results>
                            <Property Source="c" Name="ChildName"/>
                        </Results>
                        <Ordering>
                            <Order Source="c" Name="DisplayOrder"/>
                        </Ordering>
                    </Query>
                    <WhereCondition>[c].[ParentID]=[prmParentID] And [c].[ChildName] Is Not Null</WhereCondition>
                </Data>
                <Statements>
                    <ConditionalBlock>
                        <If>
                            <Condition>Not IsNull([newList])</Condition>
                            <Statements>
                                <Action Collapsed="true" Name="SetLocalVar">
                                    <Argument Name="Name">newList</Argument>
                                    <Argument Name="Value">[newList] &amp; ";" &amp; Chr(160)</Argument>
                                </Action>
                            </Statements>
                        </If>
                    </ConditionalBlock>
                    <Action Collapsed="true" Name="SetLocalVar">
                        <Argument Name="Name">newList</Argument>
                        <Argument Name="Value">[newList] &amp; [c].[ChildName]</Argument>
                    </Action>
                </Statements>
            </ForEachRecord>
            <LookUpRecord>
                <Data>
                    <Reference>Parents</Reference>
                    <WhereCondition>[Parents].[ParentID]=[prmParentID]</WhereCondition>
                </Data>
                <Statements>
                    <EditRecord>
                        <Data/>
                        <Statements>
                            <Action Collapsed="true" Name="SetField">
                                <Argument Name="Field">Parents.ChildList</Argument>
                                <Argument Name="Value">[newList]</Argument>
                            </Action>
                        </Statements>
                    </EditRecord>
                </Statements>
            </LookUpRecord>
        </Statements>
    </DataMacro>
</DataMacros>

[插入后]

AfterInsert.png

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application">
    <DataMacro Event="AfterInsert">
        <Statements>
            <Action Name="RunDataMacro">
                <Argument Name="MacroName">Children.UpdateChildList</Argument>
                <Parameters>
                    <Parameter Name="prmParentID" Value="[ParentID]"/>
                </Parameters>
            </Action>
        </Statements>
    </DataMacro>
</DataMacros>

[更新后]

AfterUpdate.png

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application">
    <DataMacro Event="AfterUpdate">
        <Statements>
            <ConditionalBlock>
                <If>
                    <Condition>Updated("ParentID") Or Updated("ChildName")</Condition>
                    <Statements>
                        <Action Name="RunDataMacro">
                            <Argument Name="MacroName">Children.UpdateChildList</Argument>
                            <Parameters>
                                <Parameter Name="prmParentID" Value="[ParentID]"/>
                            </Parameters>
                        </Action>
                        <ConditionalBlock>
                            <If>
                                <Condition>Updated("ParentID")</Condition>
                                <Statements>
                                    <Action Name="RunDataMacro">
                                        <Argument Name="MacroName">Children.UpdateChildList</Argument>
                                        <Parameters>
                                            <Parameter Name="prmParentID" Value="[Old].[ParentID]"/>
                                        </Parameters>
                                    </Action>
                                </Statements>
                            </If>
                        </ConditionalBlock>
                    </Statements>
                </If>
            </ConditionalBlock>
        </Statements>
    </DataMacro>
</DataMacros>

[删除后]

AfterDelete.png

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application">
    <DataMacro Event="AfterDelete">
        <Statements>
            <Action Name="RunDataMacro">
                <Argument Name="MacroName">Children.UpdateChildList</Argument>
                <Parameters>
                    <Parameter Name="prmParentID" Value="[Old].[ParentID]"/>
                </Parameters>
            </Action>
        </Statements>
    </DataMacro>
</DataMacros>

结果

当对子表进行更改时,父表中的列表将自动更新:

ParentID  ParentName     ChildList                        
--------  -------------  ---------------------------------
       1  Homer Simpson  Bart; Lisa; Maggie               
       2  Ned Flanders   Rod, the elder; Todd, the younger

备注

  1. [ChildList]字段仅用于显示目的。编辑该字段中的值将更改子表中的值。

  2. 列表与";" & Chr(160)分隔,以区别于实际数据中的任何";" & Chr(32)对。如果不间断空格(Chr(160))字符包含了列表,那么我们可以在查询中使用Replace()函数将";" & Chr(160)转换为";" & Chr(32)或{{ 1}}或其他最合适的东西。

  3. 要使用现有子数据填充列表,我们只需要更新&#34;每个父母的一个子记录,如此

  4. "," & Chr(32)