tat*_*tsu 2 sql postgresql tree hierarchical-data
我的数据库中有一个使用父ID链接存储的树.
我对表中数据的一个示例是:
id | name | parent id ---+-------------+----------- 0 | root | NULL 1 | Node 1 | 0 2 | Node 2 | 0 3 | Node 1.1 | 1 4 | Node 1.1.1| 3 5 | Node 1.1.2| 3
现在我想得到一个给定节点的所有直接后代的列表,但如果不存在,我想让它只返回节点本身.
我希望id = 3的子查询的返回值为:
children -------- 4 5
然后查询id = 4的子节点:
children -------- 4
我可以改变我将树存储到嵌套集的方式,但我不知道这将如何使我想要的查询成为可能.
在新的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
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅我的博客中的文章
在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';
Run Code Online (Sandbox Code Playgroud)
并从此功能中选择:
SELECT *
FROM fn_hierarchy_connect_by(4, 1)
Run Code Online (Sandbox Code Playgroud)
第一个参数是根id,第二个参数应该是1.
有关详细信息,请参阅我的博客中的这篇文章
更新:
要仅显示第一级子项,或者如果子项不存在则显示节点本身,请发出以下查询:
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
)
Run Code Online (Sandbox Code Playgroud)
这比a更有效JOIN,因为第二个查询最多只能进行两次索引扫描:第一次确保查找是否存在子项,第二次查询是否存在子项时选择父行.