使用 MYSQL 选择嵌套集树中节点的祖先和直接子节点
希望各位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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里是一个带有解决方案的SQL Fiddle。
SQL 是:
祖先是 select 语句中非常简单的子查询。
对于孩子,子查询 t3 通过查找具有 MAX(lft) 的每个节点的祖先来创建邻接列表,然后将其连接到 t4 以获取孩子的名称。
请随意将您喜欢的任何
WHERE
子句放在底部。Here is an SQL Fiddle with a solution.
The SQL is:
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.阅读这些关于 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/