我有以下查询:
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);
我试图找到从孩子到 root 的路径。 [编辑]并追加我们必须遍历的边数 目标是将孩子的父母与其父母一起加入,例如:
(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
如何在第二个查询p1
中使用第一个查询p2
的引用?
之后我应该;
(8,2,1)
(3,12,1)
(3,10,2)
(8,5,2)
因此,我已经知道如何完成我想要的工作。
答案 0 :(得分:4)
您无法从同一级别(或UNION
查询的另一个分支)中的另一个查询中的一个子查询引用表别名。表别名仅在查询本身及其子查询中可见
您可以使用LATERAL JOIN
在同一查询级别引用子查询的输出列。例如:
Find most common elements in array with a group by
仅限少数级别(如果知道最大值),您可以使用简单的查询:
LEFT JOIN
到表格本身的n-1个实例COALESCE
和CASE
语句确定root和hight,
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;
这是标准SQL,应该在您标记的所有4个RDBMS 中。
使用recursive CTE之类的@Ken已经建议。
SELECT
中,只保留每个孩子最大height
的行。
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;
DISTINCT ON
特定于 Postgres 。说明:
Select first row in each GROUP BY group?
其余的将在 Oracle 甚至 SQLite 中以类似的方式工作,但在不支持CTE的MySQL中则不行。
SQL Fiddle展示了两者。
答案 1 :(得分:2)
在 Postgres 中,我建议您查看WITH RECURSIVE
CTE :
http://www.postgresql.org/docs/9.3/static/queries-with.html
它非常适合建模树状结构,如父子关系,无论是整棵树,子树等等。
Postgres doc中有很多例子,包括专门处理树状结构,应该适用于你的情况(尽管你的查询有一些调整以适应{{1} }模具)。
答案 2 :(得分:2)
无法在第二个SELECT中引用第一个SELECT的表别名(在UNION或UNION ALL集合运算符之后。您可以在相关子查询中,但必须在相关子查询的上下文中)相同的SELECT。)
另外,你需要在语句中抛弃分号; MySQL将把这看作是声明的结尾。
对于 MySQL ,你肯定有一个可行的方法来解决这个问题,为每个&#34; height&#34;使用单独的查询,并将结果与{{ 1}}设置运算符。可能,您希望使用UNION
集合运算符来提高性能。 (如果您不需要额外的步骤来识别和删除重复项。此外,它不需要使用内联视图。
UNION ALL
只是为了演示如何将其扩展到3的高度,将另一个JOIN添加到同一个表中,别名为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)
。
p3
注意强>
最初,我只注意到它被标记为MySQL。
使用Oracle,您可以使用递归 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,以获得没有CONNECT BY
的等效结果。