Mysql 在另一个查询中使用表别名遍历树
我有以下疑问:Mysql 在另一个查询中使用表别名遍历树,mysql,sql,oracle,sqlite,postgresql,Mysql,Sql,Oracle,Sqlite,Postgresql,我有以下疑问: select * from ( select p1.c as child, p1.p as parent, 1 as height from parent as p1 where (p1.c=3 or p1.c=8); union select p2.c as child, p2.c as parent, 2 as height from parent as p2 where (p1.child=3 or p1.child=8) a
select * from (
select p1.c as child, p1.p as parent, 1 as height
from parent as p1
where (p1.c=3 or p1.c=8);
union
select p2.c as child, p2.c as parent, 2 as height
from parent as p2
where (p1.child=3 or p1.child=8) and p1.parent = p2.child;
)
模式是:
CREATE TABLE parent(p int, c int);
我试图找到一条从孩子到根的路径。[编辑]并附加我们必须遍历的边数。
目标是将孩子的父母与其父母结合在一起,类似于:
(8, 2, 1)
(8, 5, 2) -> 8 is the lowest child, 2 is its parent, and 5 it's 2 parent.
一些样本数据:
10 | 5
10 | 12
12 | 3
12 | 4
4 | 6
4 | 7
5 | 11
5 | 2
2 | 8
如何在将形成p2的第二个查询中使用第一个查询p1的引用?
在那之后,我应该已经
(8,2,1)
(3,12,1)
(3,10,2)
(8,5,2)
因此,我已经知道如何完成我想要的内容。在Postgres中,我建议使用递归CTE查看:
它非常适合于建模类似于树的结构,例如父子关系,可以是整个树、子树等
Postgres doc中有很多例子,包括专门处理树状结构,这应该适用于您的情况,尽管您的查询进行了一些调整,以适应递归模型。不可能在UNION或UNION ALL set运算符之后的第二个SELECT中引用第一个SELECT中的表别名。您可以在相关子查询中进行查询,但必须在同一个SELECT的上下文中 此外,您需要在语句中去掉分号;MySQL将把这看作是语句的结尾 对于MySQL,您肯定有一个可行的方法来解决这个问题,对每个高度使用单独的查询,并将结果与联合集操作符相结合。可能需要使用UNION ALL set运算符来提高性能。如果您不需要识别和删除重复项的额外步骤。此外,不必使用内联视图
SELECT p1.c AS child
, p1.p AS parent
, 1 AS height
FROM parent p1
WHERE p1.c IN (3,8)
UNION ALL
SELECT p1.c AS child
, p2.p AS parent
, 2 AS height
FROM parent p1
JOIN parent p2
ON p2.c = p1.p
WHERE p1.c IN (3,8)
为了演示如何将其扩展到3的高度,在同一个表中添加另一个别名为p3的联接
注
最初,我只注意到这是为MySQL标记的
使用Oracle,您可以使用SELECT形式的递归连接,在不使用UNION的情况下获得等效的结果。有问题吗
不能在同一级别的另一个查询或联合查询的另一分支中引用来自一个子查询的表别名。表别名仅在查询本身及其子查询中可见。
您可以在同一查询级别上使用引用子查询的输出列。例子:
最小最大级别数的解决方案
如果您知道最大值,则可以使用一个简单的查询:
左连接到表本身的n-1个实例
使用COALESCE和CASE语句确定根和高度,
这是标准SQL,应该适用于您标记的所有4个RDBMS
任意级别数的通用解决方案
使用一个像@Ken已经建议过的
在递归分支中,为每一行保留子级,仅前进父级。
在“外部选择”中,仅保留每个子级高度最大的行。
DISTINCT ON是专为博士后设计的。说明:
其余部分将以类似的方式在Oracle甚至SQLite中工作,但在不支持CTE的MySQL中则不行
两者都演示。如果使用Oracle,请查找CONNECT BY,或者混合在一个列表中。这些示例对我来说很好。第三列是高度,即节点之间的距离。第一列是孩子,第二列是父母身高1,或祖父母身高2。@spencer7593:现在,加起来就是了。谢谢。您的树是否像示例中那样被限制为三个级别,或者您正在寻找n个级别的通用解决方案?为什么这个问题用4个不同的DBMS标记?
UNION ALL
SELECT p1.c AS child
, p3.p AS parent
, 3 AS height
FROM parent p1
JOIN parent p2 ON p2.c = p1.p
JOIN parent p3 ON p3.c = p2.p
WHERE p1.c IN (3,8)
SELECT p1.c AS child, COALESCE(p3.p, p2.p, p1.p) AS parent
,CASE
WHEN p3.p IS NOT NULL THEN 3
WHEN p2.p IS NOT NULL THEN 2
ELSE 1
END AS height
FROM parent p1
LEFT JOIN parent p2 ON p2.c = p1.p
LEFT JOIN parent p3 ON p3.c = p2.p
WHERE p1.c IN (3, 8)
ORDER BY p1.c;
WITH RECURSIVE cte AS (
SELECT c AS child, p AS parent, 1 AS height
FROM parent
WHERE c IN (3, 8)
UNION ALL
SELECT c.child, p.p AS parent, c.height + 1
FROM cte c
JOIN parent p ON p.c = c.parent
-- WHERE c.height < 10 -- to safeguard against endless loops if necessary
)
SELECT DISTINCT ON (child) *
FROM cte
ORDER BY child, height DESC;