SQL 查找树中的所有直系后代
Posted
技术标签:
【中文标题】SQL 查找树中的所有直系后代【英文标题】:SQL Find all direct descendants in a tree 【发布时间】:2009-07-17 18:03:52 【问题描述】:我的数据库中有一个使用父 ID 链接存储的树。
我对表中数据的示例是:
编号 |姓名 |父母身份证 ---+--------------+------------ 0 |根 |空值 1 |节点 1 | 0 2 |节点 2 | 0 3 |节点 1.1 | 1 4 |节点 1.1.1 | 3 5 |节点 1.1.2 | 3现在我想获取给定节点的所有直接后代的列表,但如果不存在,我希望它只返回节点本身。
我希望 id = 3 的孩子的查询返回为:
孩子们 -------- 4 5那么查询id=4的孩子为:
孩子们 -------- 4我可以更改将树存储到嵌套集的方式,但我不知道这将如何使我想要的查询成为可能。
【问题讨论】:
我知道如何使用游标或 CTE 来做到这一点,但那是 SQL Server。 【参考方案1】:在新的PostgreSQL 8.4
中,您可以使用CTE
:
WITH RECURSIVE q AS
(
SELECT h, 1 AS level, ARRAY[id] AS breadcrumb
FROM t_hierarchy h
WHERE parent = 0
UNION ALL
SELECT hi, q.level + 1 AS level, breadcrumb || id
FROM q
JOIN t_hierarchy hi
ON hi.parent = (q.h).id
)
SELECT REPEAT(' ', level) || (q.h).id,
(q.h).parent,
(q.h).value,
level,
breadcrumb::VARCHAR AS path
FROM q
ORDER BY
breadcrumb
详情请看我博客中的这篇文章:
PostgreSQL 8.4
: preserving order for hierarchical query
在8.3
或更早的版本中,您必须编写一个函数:
CREATE TYPE tp_hierarchy AS (node t_hierarchy, level INT);
CREATE OR REPLACE FUNCTION fn_hierarchy_connect_by(INT, INT)
RETURNS SETOF tp_hierarchy
AS
$$
SELECT CASE
WHEN node = 1 THEN
(t_hierarchy, $2)::tp_hierarchy
ELSE
fn_hierarchy_connect_by((q.t_hierarchy).id, $2 + 1)
END
FROM (
SELECT t_hierarchy, node
FROM (
SELECT 1 AS node
UNION ALL
SELECT 2
) nodes,
t_hierarchy
WHERE parent = $1
ORDER BY
id, node
) q;
$$
LANGUAGE 'sql';
并从此函数中选择:
SELECT *
FROM fn_hierarchy_connect_by(4, 1)
第一个参数是根id
,第二个应该是1
。
更多详情请参阅我博客中的这篇文章:
Hierarchical queries inPostgreSQL
更新:
要仅显示第一级子节点,如果子节点不存在,则显示节点本身,请发出以下查询:
SELECT *
FROM t_hierarchy
WHERE parent = @start
UNION ALL
SELECT *
FROM t_hierarchy
WHERE id = @start
AND NOT EXISTS
(
SELECT NULL
FROM t_hierarchy
WHERE parent = @start
)
这比JOIN
更有效,因为第二个查询最多只进行两次索引扫描:第一个确保找出是否存在子行,第二个查询如果不存在则选择父行有孩子。
【讨论】:
这个问题是我希望它只显示第一级子节点,如果没有,只返回节点本身。在摆弄了更多之后,我给出了一个对我有用的答案。 +1 好答案!我目前正在努力解决这个问题,如果您能确认这仍然是您在最新 PostgreSQL 版本中解决问题的方式,我将不胜感激。此外,理想情况下,我正在寻找一种适用于 PosgreSQL 和 H2 的解决方案 @JacobusR:第一个查询是您应该在 9.2 中使用的内容 谢谢,只是为了让你知道,我读了你的博客。绝对棒!再次感谢。【参考方案2】:找到了一个符合我要求的查询。
选择 * 从 ( SELECT id FROM t_tree WHERE name = '' ) 作为我, t_tree g 在哪里 ( ( (i.id = g.id) 和 不存在(SELECT * FROM t_tree WHERE parentid = i.id))或 ( ( (i.id = g.parentid) 和 EXISTS (SELECT * FROM t_tree WHERE parentid = i.id))【讨论】:
以上是关于SQL 查找树中的所有直系后代的主要内容,如果未能解决你的问题,请参考以下文章