获取 parent 的所有可能 childs/decendants

Get all possible childs/decendants of a parent

我搜索了很多,但找不到可用于 MS Access 的任何内容,我找到了 SQL 的解决方案,但访问 SQL 中不允许使用的语句。

因此,在 MS access 2019 中,我有一个 table tbContentList,其中包含 Id 和 ParentID。我想要的是显示特定 parent.

的所有 childs/decendants

我的 table 看起来像这样:

如果我想显示 Id 3 的所有孩子,我想以结果结束:

这在 MS 访问查询中是否可行? VBA 是可能的,但我认为用查询来做会更快。有人可以帮我解决这个问题吗?

相当于SQL: https://www.codeproject.com/Articles/818694/SQL-Queries-to-Manage-Hierarchical-or-Parent-child (所有可能的孩子)

您有多种选择。但是,一个不会做,这是一个仅使用 SQL 的递归查询; Access 不会被愚弄,并且会声明循环引用。您唯一的机会是创建一个仅解析有限数量级别(例如 8 或 10)的查询。

但是您可以在像 DLookup() 这样的域聚合函数中涵盖递归调用。但是,这非常慢,因为调用查询的 DLookup() 将为每条记录 运行。对于超过几十条记录,这很可能是 unacceptable.

我发现,对于无限数量的级别,最快的方法是创建一个查找函数,它为每条记录遍历树。这可以输出记录的级别或由记录的键和上面的所有键构建的复合键。

由于查找函数将在每次调用时使用相同的记录集,您可以将其设置为 static,并且(对于 Jet)您可以通过使用 Seek 定位记录来进一步改进.

这是一个类似案例的例子,它会给你一个想法:

Public Function RecursiveLookup(ByVal lngID As Long) As String

    Static dbs      As DAO.Database
    Static tbl      As DAO.TableDef
    Static rst      As DAO.Recordset

    Dim lngLevel    As Long
    Dim strAccount  As String

    If dbs Is Nothing Then
        ' For testing only.
        ' Replace with OpenDatabase of backend database file.
        Set dbs = CurrentDb
        Set tbl = dbs.TableDefs("tblAccount")
        Set rst = dbs.OpenRecordset(tbl.Name, dbOpenTable)
    End If

    With rst
        .Index = "PrimaryKey"
        While lngID > 0
            .Seek "=", lngID
            If Not .NoMatch Then
                lngLevel = lngLevel + 1
                lngID = !MasterAccountFK.Value
                If lngID > 0 Then
                    strAccount = str(!AccountID) & strAccount
                End If
            Else
                lngID = 0
            End If
        Wend
        ' Leave recordset open.
        ' .Close
    End With

    '  Don't terminate static objects.
    '  Set rst = Nothing
    '  Set tbl = Nothing
    '  Set dbs = Nothing

    '  Alternative expression for returning the level.
    '  (Adjust vartype of return value of function.)
    '  RecursiveLookup = lngLevel ' As Long
    RecursiveLookup = strAccount

End Function

这假设 table 具有主键 ID 和指向父记录的外(主)键 - 以及可见键 (AccountID) 为 0 的顶级记录(未使用)。

现在,使用这样的查询(其中 Account 将是可见的复合键),您的树几乎可以立即很好地显示出来:

SELECT
    *, RecursiveLookup([ID]) AS Account
FROM
    tblAccount
WHERE
    (AccountID > 0)
ORDER BY
    RecursiveLookup([ID]);

因此,我能够修改 的逻辑并使其适合我的项目。我将父结果放在分隔符“;”之间。这使得在查询中查找特定 ContentID 的后代变得更加容易。此外,我必须处理父列中的 Null 值,因为某些 ContentID 是树的开头。

Public Function GetParentIDs(ByVal lContentID As Long) As String
    Static dbs As DAO.Database
    Static tbl As DAO.TableDef
    Static rst As DAO.Recordset
    Dim strParents As String

    If dbs Is Nothing Then
        ' For testing only.
        ' Replace with OpenDatabase of backend database file.
        Set dbs = CurrentDb
        Set tbl = dbs.TableDefs("tbContentList")
        Set rst = dbs.OpenRecordset(tbl.Name, dbOpenTable)
    End If

    With rst
        .Index = "PrimaryKey"
        Do While lContentID > 0
            .Seek "=", lContentID
            If Not .NoMatch Then
                lContentID = Nz(!ParentID.Value, 0)
                If lContentID > 0 Then
                    strParents = ";" & CStr(lContentID) & strParents
                Else
                    Exit Do
                End If
            Else
                Exit Do
            End If
        Loop
        ' Leave recordset open.
        ' .Close
    End With

    '  Don't terminate static objects.
    '  Set rst = Nothing
    '  Set tbl = Nothing
    '  Set dbs = Nothing

    'Return value
    If strParents = "" Then
        GetParentIDs = ""
    Else
        GetParentIDs = strParents & ";"
    End If
End Function

从特定 ContentID 获取所有后代的查询。对于此示例,3 if 可以更改为另一个值。

SELECT tbContentList.[ContentID], tbContentList.[ParentID], tbContentList.[Item], GetParentIDs([ContentID]) AS Parents
FROM tbContentList
WHERE (((GetParentIDs([ContentID])) Like '*;3;*'));

感谢您的帮助,让我走上了正确的方向。