获取 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;*'));
感谢您的帮助,让我走上了正确的方向。
我搜索了很多,但找不到可用于 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]);
因此,我能够修改
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;*'));
感谢您的帮助,让我走上了正确的方向。