我有一个 MySQL 查询,我认为它可以很好地检索每个节点的所有祖先,从顶级节点开始,向下到其直接节点。但是,当我向嵌套集中添加第 5 层时,它就坏了。
下面是示例表、查询和 SQL Fiddles:
四层嵌套集:
CREATE TABLE Tree
(title varchar(20) PRIMARY KEY,
`tree` int,
`left` int,
`right` int);
INSERT Tree
VALUES
("Food", 1, 1, 18),
('Fruit', 1, 2, 11),
('Red', 1, 3, 6),
('Cherry', 1, 4, 5),
('Yellow', 1, 7, 10),
('Banana', 1, 8, 9),
('Meat', 1, 12, 17),
('Beef', 1, 13, 14),
('Pork', 1, 15, 16);
查询:
SELECT t0.title node
,(SELECT GROUP_CONCAT(t2.title)
FROM Tree t2
WHERE t2.left<t0.left AND t2.right>t0.right
ORDER BY t2.left) ancestors
FROM Tree t0
GROUP BY t0.title;
节点 Banana
的返回结果是 Food,Fruit,Yellow
- 完美。你可以在这里看到这个SQL Fiddle - 4 Levels
当我在下面的 5 级表上运行相同的查询时,第 5 级节点以错误的顺序返回:
CREATE TABLE Tree
(title varchar(20) PRIMARY KEY,
`tree` int,
`left` int,
`right` int);
INSERT Tree
VALUES
("Food", 1, 1, 24),
('Fruit', 1, 2, 13),
('Red', 1, 3, 8),
('Cherry', 1, 4, 7),
('Cherry_pie', 1, 5, 6),
('Yellow', 1, 9, 12),
('Banana', 1, 10, 11),
('Meat', 1, 14, 23),
('Beef', 1, 15, 16),
('Pork', 1, 17, 22),
('Bacon', 1, 18, 21),
('Bacon_Sandwich', 1, 19, 20);
Bacon_Sandwich
的返回结果是 Bacon,Food,Meat,Pork
顺序不对,应该是 Food,Meat,Pork,Bacon
- 你可以在这里看到 SQL Fiddle - 5 Levels
我不确定发生了什么,因为我不太了解子查询。任何人都可以阐明这一点吗?
调查后编辑:
哇!!看起来写出所有这些并阅读有关使用 GROUP_CONCAT
进行排序的内容给了我一些灵感。
将 ORDER BY
添加到实际的 GROUP_CONCAT
函数并从子查询的末尾删除解决了这个问题。我现在收到节点 Bacon_Sandwich
的 Food,Meat,Pork,Bacon
SELECT t0.title node
,(SELECT GROUP_CONCAT(t2.title ORDER BY t2.left)
FROM Tree t2
WHERE t2.left<t0.left AND t2.right>t0.right
) ancestors
FROM Tree t0
GROUP BY t0.title;
虽然我仍然不知道为什么。在子查询末尾有 ORDER BY
适用于 4 个级别但不适用于 5 个级别?!?!
如果有人可以解释问题是什么以及为什么移动 ORDER BY
可以解决问题,我将不胜感激。
最佳答案
首先了解您有一个 implicit GROUP BY
很重要
If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows.
为了使这一点更易于理解,我将省略子查询并将问题简化为香蕉。香蕉是集合 [10, 11]。正确排序的祖先是那些:
SELECT "banana" as node, GROUP_CONCAT(title ORDER by `left`)
FROM Tree WHERE `left` < 10 AND `right` > 11
GROUP BY node;
ORDER BY
必须在 GROUP_CONCAT()
中,因为您希望聚合函数进行排序。 ORDER BY
按聚合结果(即 GROUP_CONCAT()
的结果)外部排序。它一直工作到 4 级的事实只是运气。 ORDER BY
对聚合函数没有影响。无论是否使用 ORDER BY
,您都会得到相同的结果:
SELECT GROUP_CONCAT(title)
FROM Tree WHERE `left` < 10 AND `right` > 11
/* ORDER BY `left` */
这可能有助于理解什么
SELECT GROUP_CONCAT(title ORDER BY left) FROM Tree WHERE … ORDER BY left
做:
获取一个选择(
WHERE
),它以未定义的顺序产生三行:("Food") ("Yellow") ("Fruit")
将结果聚合到一行(隐式
GROUP BY
)以便能够使用聚合函数:(("Food","Yellow", "Fruit"))
在其上触发聚合函数 (
GROUP_CONCAT(title, ORDER BY link)
)。 IE。按链接排序,然后连接:("Food,Fruit,Yellow")
现在终于对结果进行排序 (
ORDER BY
)。因为它只有一行,所以排序不会改变任何内容。("Food,Fruit,Yellow")
关于mysql - 嵌套集查询以检索每个节点的所有祖先,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20993518/