使用 MYSQL 选择嵌套集树中节点的祖先和直接子节点

发布于 2024-08-20 18:51:48 字数 2019 浏览 8 评论 0原文

希望各位mysql专家能够帮助我。

我有存储在嵌套集中的搜索标签数据。

TABLE searchTags

searchTagID
searchTag
lft
rgt

(我使用嵌套集,因为有时我需要轻松选择树的整个分支。)

我想构造一个查询,该查询将返回与 LIKE 匹配的节点结果集、每个节点的祖先以及每个节点的直接子节点。

例如,如果这是我的嵌套集...

                          1_tagA_22
     2_tagB1_11          12_tagB2_13           14_tagB3_21
3_taC1_4   5_taC2_10                                   15_tagC3_20
               6_tagD1_9                        16_tagD2_17    18_tagD3_19
                  7_tagE1_8

...对于我的搜索针,我有 LIKE CONCAT('%','tagc','%'),我想返回如下所示的内容

searchTag   |   ancestors   |  immediateChildren
tagC1          tagB1,tagA       NULL
tagC2         tagB1,tagA       tagD1
tagC3          tagB3,tagA       tagD2,tagD3

:目前我正在通过多个查询来执行此操作。首先,我选择搜索标签及其祖先的结果集。然后我循环遍历这个结果集,对于每个结果,我执行另一个选择来获取直接子项。 (我在下面包含这些查询,以供参考。)

这种方法有效,但我有一种感觉,这是一个低效的解决方案,并且迟早会崩溃。 :) 我想知道是否有更好的方法来做到这一点 - 即有没有一种方法可以将所有这些组合成一个更有效的单个 SELECT 语句?

任何建议将不胜感激。

谢谢!

参考: 我使用以下命令来选择搜索标签和祖先的路径...

    SELECT 

        node.searchTag, 

        GROUP_CONCAT(parent.searchTag 
        ORDER BY parent.lft DESC
        SEPARATOR '; ') AS ancestors 


    FROM 

        searchTags AS node,
        searchTags AS parent

    WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND parent.lft < node.lft
    AND node.searchTag LIKE CONCAT('%','tagc','%')
    GROUP BY node.searchTagID;

...然后循环遍历此结果集,并为每个结果运行另一个查询以获取直接子级(使用 mrbinky3000 的出色方法):

SELECT lft, rgt INTO @parent_left, @parent_right FROM searchTags WHERE searchTagID = $id;

SELECT 

    GROUP_CONCAT(child.searchTag SEPARATOR "; ") as searchTag

FROM searchTags AS child
LEFT JOIN searchTags AS ancestor ON
    ancestor.lft BETWEEN @parent_left+1 AND @parent_right-1 AND
    child.lft BETWEEN ancestor.lft+1 AND ancestor.rgt-1
WHERE
    child.lft BETWEEN @parent_left+1 AND @parent_right-1 AND
    ancestor.searchTagID IS NULL;

Hoping some of you mysql experts can help me out.

I have searchtag data that is stored in a nested set.

TABLE searchTags

searchTagID
searchTag
lft
rgt

(I am using nested sets because there are times when I need to easily select entire branches of the tree.)

I would like to construct a query that will return a resultset of nodes matched with LIKE, the ancestors of each of these nodes, and the immediate children of each of these nodes.

For example, if this is my nested set...

                          1_tagA_22
     2_tagB1_11          12_tagB2_13           14_tagB3_21
3_taC1_4   5_taC2_10                                   15_tagC3_20
               6_tagD1_9                        16_tagD2_17    18_tagD3_19
                  7_tagE1_8

...and for my search needle I have LIKE CONCAT('%','tagc','%'), I would like to return something that looks like this:

searchTag   |   ancestors   |  immediateChildren
tagC1          tagB1,tagA       NULL
tagC2         tagB1,tagA       tagD1
tagC3          tagB3,tagA       tagD2,tagD3

I am currently doing this with multiple queries. First I select a resultset of searchtags and their ancestors. Then I loop through this resultset and for each result, I do another select to get the immediate children. (I am including these queries below, for reference.)

This method works, but I have a feeling it is an inefficient solution and is likely to blow up sooner or later. :) I am wondering if there is a better way of doing this - ie is there a way to combine all of this into a single SELECT statement that is more efficient?

Any advice would be much appreciated.

Thanks!

Reference:
I use the following to select the searchtag and the path of ancestors...

    SELECT 

        node.searchTag, 

        GROUP_CONCAT(parent.searchTag 
        ORDER BY parent.lft DESC
        SEPARATOR '; ') AS ancestors 


    FROM 

        searchTags AS node,
        searchTags AS parent

    WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND parent.lft < node.lft
    AND node.searchTag LIKE CONCAT('%','tagc','%')
    GROUP BY node.searchTagID;

...and then I loop through this resultset and for each result run another query to get the immediate children (using mrbinky3000's excellent method):

SELECT lft, rgt INTO @parent_left, @parent_right FROM searchTags WHERE searchTagID = $id;

SELECT 

    GROUP_CONCAT(child.searchTag SEPARATOR "; ") as searchTag

FROM searchTags AS child
LEFT JOIN searchTags AS ancestor ON
    ancestor.lft BETWEEN @parent_left+1 AND @parent_right-1 AND
    child.lft BETWEEN ancestor.lft+1 AND ancestor.rgt-1
WHERE
    child.lft BETWEEN @parent_left+1 AND @parent_right-1 AND
    ancestor.searchTagID IS NULL;

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

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

发布评论

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

评论(2

橘虞初梦 2024-08-27 18:51:48

这里是一个带有解决方案的SQL Fiddle。

SQL 是:

SELECT t0.title node
      ,GROUP_CONCAT(t5.title) children
      ,(SELECT GROUP_CONCAT(t6.title)
                    FROM Tree t6
                    WHERE t6.lft<t0.lft AND t6.rgt>t0.rgt
                    ORDER BY t6.lft) ancestors
FROM Tree t0
     LEFT JOIN
     (SELECT *
      FROM (SELECT t1.lft node
                  ,MAX(t2.lft) nodeparent
            FROM Tree t1
                 INNER JOIN
                 Tree t2 ON t1.lft>t2.lft AND t1.rgt<t2.rgt
            GROUP BY t1.lft) t3 
            LEFT JOIN
            Tree t4 ON t3.node=t4.lft) t5 ON t0.lft=t5.nodeparent
GROUP BY t0.title;

祖先是 select 语句中非常简单的子查询。

对于孩子,子查询 t3 通过查找具有 MAX(lft) 的每个节点的祖先来创建邻接列表,然后将其连接到 t4 以获取孩子的名称。

请随意将您喜欢的任何 WHERE 子句放在底部。

Here is an SQL Fiddle with a solution.

The SQL is:

SELECT t0.title node
      ,GROUP_CONCAT(t5.title) children
      ,(SELECT GROUP_CONCAT(t6.title)
                    FROM Tree t6
                    WHERE t6.lft<t0.lft AND t6.rgt>t0.rgt
                    ORDER BY t6.lft) ancestors
FROM Tree t0
     LEFT JOIN
     (SELECT *
      FROM (SELECT t1.lft node
                  ,MAX(t2.lft) nodeparent
            FROM Tree t1
                 INNER JOIN
                 Tree t2 ON t1.lft>t2.lft AND t1.rgt<t2.rgt
            GROUP BY t1.lft) t3 
            LEFT JOIN
            Tree t4 ON t3.node=t4.lft) t5 ON t0.lft=t5.nodeparent
GROUP BY t0.title;

The ancestors are a pretty straightforward subquery in the select statement.

For the children, subquery t3 creates an adjacency list by finding the ancestor of each nod that has MAX(lft) which is then joined to t4 to get the childrens name.

Feel free to put any WHERE clause you like at the bottom.

追星践月 2024-08-27 18:51:48

阅读这些关于 MySQL 中嵌套集的好文章
http://explainextend.com/2009/03/17/hierarchical-queries-in-mysql/>http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

Have a read of these good articles on nested sets in MySQL
http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/>http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

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