MS ACCESS - 层次树排序

发布于 2024-07-30 00:31:21 字数 974 浏览 2 评论 0原文

我正在努力解决排序问题。

我有一个如下表:

aspect_id (int)
aspect_text (memo)
root_id (int) which has as a foreign key a aspect_id

我有一个包含以下虚拟数据的非循环树:

aspect_id  aspect_text  root_id 

1          root         null
2          aspect1      1
3          aspect2      1
4          aspect3      2
5          aspect5      4

在示例中,数据排序正确,但在我的数据库中则不然。 我想对其从根元素开始进行排序,然后找到一个子元素,输出该子元素并递归地执行此操作。

对于 CTE,这是相当可行的。 Access 不支持此功能。 对于 CTE,它会是这样的:

WITH aspectTree (aspect_id, root_id, Level#) AS 
(
        Select 
            aspect.aspect_id, 
            aspect.root_id,
            0
        FROM aspect
        WHERE aspect.aspect_id = 44
    UNION ALL
        SELECT 
            aspect.aspect_id, 
            aspect.root_id, 
            T.Level# + 1
        FROM aspect
        INNER JOIN aspectTree AS T 
            On T.aspect_id = aspect.root_id
)
SELECT * FROM aspectTree;

I'm struggling with a sorting problem.

I've got a table which is as follows:

aspect_id (int)
aspect_text (memo)
root_id (int) which has as a foreign key a aspect_id

I've got a non cyclic tree with the following dummy data:

aspect_id  aspect_text  root_id 

1          root         null
2          aspect1      1
3          aspect2      1
4          aspect3      2
5          aspect5      4

In the example the data is sorted correctly, in my database its not. I want to sort that it starts at the root element, then finds a child, output that child and does that recursively.

With CTE it is fairly doable. Access doesn't support this. With CTE it would be something like:

WITH aspectTree (aspect_id, root_id, Level#) AS 
(
        Select 
            aspect.aspect_id, 
            aspect.root_id,
            0
        FROM aspect
        WHERE aspect.aspect_id = 44
    UNION ALL
        SELECT 
            aspect.aspect_id, 
            aspect.root_id, 
            T.Level# + 1
        FROM aspect
        INNER JOIN aspectTree AS T 
            On T.aspect_id = aspect.root_id
)
SELECT * FROM aspectTree;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉月流沐 2024-08-06 00:31:21

如果不考虑性能,那么这个相当简单的解决方案将起作用:

Public Function GetLevel(ByVal lngNodeId As Long) As Long

    Dim varRootId As Variant

    varRootId = DLookup("root_id", "aspect", "aspect_id=" & lngNodeId)

    If IsNull(varRootId) Then
        GetLevel = 0
    Else
        GetLevel = GetLevel(varRootId) + 1
    End If

End Function

然后您可以在 ORDER BY 子句中使用该函数:

SELECT aspect.*
FROM aspect
ORDER BY GetLevel([aspect_id]), aspect_text

If performance is not a consideration, this fairly simple solution would work:

Public Function GetLevel(ByVal lngNodeId As Long) As Long

    Dim varRootId As Variant

    varRootId = DLookup("root_id", "aspect", "aspect_id=" & lngNodeId)

    If IsNull(varRootId) Then
        GetLevel = 0
    Else
        GetLevel = GetLevel(varRootId) + 1
    End If

End Function

You could then use that function in your ORDER BY clause:

SELECT aspect.*
FROM aspect
ORDER BY GetLevel([aspect_id]), aspect_text
故事和酒 2024-08-06 00:31:21

我不知道以下内容是否适合您,但您可以使用物料清单算法。

I don't know if the following will work for you but here you go using Bill of Materials algorithms.

做个ˇ局外人 2024-08-06 00:31:21

它充满了测试代码,但我做了一些可以在 vb 代码中运行的东西。 它确实丑陋且缓慢,但它确实有效。 我现在正在清理它,刚刚开始工作。 解决方案是递归函数。 如果该函数发现该节点有子节点,则会调用自身。 它似乎覆盖了数组,这就是为什么它是数组的数组。 该代码很丑陋,但它有效,这就是我所需要的。 数据库现在和将来都很小(<1000 条记录),因此速度不是问题。 感谢您的评论和回答,如果有人知道更好的解决方案,我很想听听。

Private Function Fillarray(value As Integer)
Dim done As Boolean

j = j + 1
esql = "select aspect_id from aspect where root_id = " & value
Set rec(j) = db.OpenRecordset(esql)
Dim k As Integer
k = j
Do While Not rec(k).EOF
done = True
arra(i) = rec(k).Fields(0) 
Dim temp1 As String
temp1 = DLookup("[aspects]", "[aspect]", "[aspect_id] = " & rec(k).Fields(0))
db.Execute "INSERT INTO sortedaspect (aspect_id, aspect) VALUES (" & rec(k).Fields(0) & ", '" & temp1 & "')"

        esql = "select aspect_id from aspect where root_id = " & rec(k).Fields(0)

        Set rec(90) = db.OpenRecordset(esql)
        Do While Not rec(90).EOF And done
            'fix this without a loop,you only need to know if it has childs...
            Fillarray (rec(k).Fields(0))
            done = False

        Loop
      'next child

rec(k).MoveNext
'value = arra(i)
i = i + 1
'MsgBox arra(i - 1)
Loop

End Function

Its full of test code, but i did something that works in vb code. Its really ugly and slow, but it works. Im now cleaning it up, just got it working. The solution is a recursive function. The function calls on itself if it finds that the node has childs. It seemed to overwrite the arrays, that why its an array of arrays. The code is hideous, but it works and thats all i needed. The database is and will stay small (<1000 records) so speed is not an issue. Thanks for the comments and answers, if someones knows i better solution, i would love to hear it.

Private Function Fillarray(value As Integer)
Dim done As Boolean

j = j + 1
esql = "select aspect_id from aspect where root_id = " & value
Set rec(j) = db.OpenRecordset(esql)
Dim k As Integer
k = j
Do While Not rec(k).EOF
done = True
arra(i) = rec(k).Fields(0) 
Dim temp1 As String
temp1 = DLookup("[aspects]", "[aspect]", "[aspect_id] = " & rec(k).Fields(0))
db.Execute "INSERT INTO sortedaspect (aspect_id, aspect) VALUES (" & rec(k).Fields(0) & ", '" & temp1 & "')"

        esql = "select aspect_id from aspect where root_id = " & rec(k).Fields(0)

        Set rec(90) = db.OpenRecordset(esql)
        Do While Not rec(90).EOF And done
            'fix this without a loop,you only need to know if it has childs...
            Fillarray (rec(k).Fields(0))
            done = False

        Loop
      'next child

rec(k).MoveNext
'value = arra(i)
i = i + 1
'MsgBox arra(i - 1)
Loop

End Function
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文