递归 parent child 查询 - postgresql
Recursive parent child query - postgresql
我正在尝试准备一个递归查询,它将在单个 table.
中生成关于 parent-child 关系的数据
这是一些测试数据:
CREATE TABLE test
(
id INTEGER,
parent INTEGER
);
INSERT INTO test (id, parent) VALUES
(2, 1),
(3, 1),
(7, 2),
(8, 3),
(9, 3),
(10, 8),
(11, 8);
1
/ \
2 3
/ / \
7 8 9
/ \
10 11
Excepted results:
-- id | ancestry | parent |
-- 1 | {1} | 1 |
-- 2 | {1,2} | 1 |
-- 3 | {1,3} | 1 |
-- 7 | {1,2,7} | 2 |
-- 8 | {1,3,8} | 3 |
-- 9 | {1,3,9} | 3 |
-- 10 | {1,3,8,10} | 8 |
-- 11 | {1,3,8,11} | 8 |
#Query 1 : Return 所有 parents for children 11 - {1,3,8,11}。这里的问题是我不知道如何标记11的第一个parent是8.
WITH RECURSIVE c AS (
SELECT 11 AS id
UNION
SELECT t.parent
FROM test AS t
JOIN c ON c.id = t.id
)
SELECT * FROM c;
提前致谢。
你可以携带一个计数器来查看在层次结构中的位置。
WITH RECURSIVE
c
AS
(
SELECT 11 AS id,
0 AS n
UNION ALL
SELECT t.parent,
c.n + 1
FROM test AS t
INNER JOIN c
ON c.id = t.id
)
SELECT *
FROM c
ORDER BY n;
8 在您的示例中将有 1,因此将其指定为第一个父级。
db<>fiddle
编辑:
在此基础上,您可以将锚点集扩展到所有节点。有点不幸的是没有 1 的条目。快速修复是 UNION ALL
也为它创建一条记录(但是你应该通过将记录 (1, NULL)
插入 test
来永久修复此问题.).让第三列携带层次结构开始的实际叶子和最后的GROUP BY
。使用 array_agg()
获取祖先数组。 (过滤 NULL
节点,一旦你将 (1, NULL)
插入到 test
中,这些节点就会在那里。)要获得叶子的直接父级,你可以使用 max()
(或 min()
) 在计数器为 1 的 id 过滤上。
WITH RECURSIVE
c
AS
(
SELECT 1 AS leaf,
1 AS parent,
0 AS n
UNION ALL
SELECT id AS leaf,
id AS parent,
0 AS n
FROM test
UNION ALL
SELECT leaf,
t.parent,
c.n + 1
FROM test AS t
INNER JOIN c
ON c.parent = t.id
)
SELECT leaf AS id,
array_agg(parent ORDER BY n DESC) FILTER (WHERE parent IS NOT NULL) AS ancestry,
max(parent) FILTER (WHERE n = 1) AS parent
FROM c
GROUP BY leaf
ORDER BY leaf;
我正在尝试准备一个递归查询,它将在单个 table.
中生成关于 parent-child 关系的数据这是一些测试数据:
CREATE TABLE test
(
id INTEGER,
parent INTEGER
);
INSERT INTO test (id, parent) VALUES
(2, 1),
(3, 1),
(7, 2),
(8, 3),
(9, 3),
(10, 8),
(11, 8);
1
/ \
2 3
/ / \
7 8 9
/ \
10 11
Excepted results:
-- id | ancestry | parent |
-- 1 | {1} | 1 |
-- 2 | {1,2} | 1 |
-- 3 | {1,3} | 1 |
-- 7 | {1,2,7} | 2 |
-- 8 | {1,3,8} | 3 |
-- 9 | {1,3,9} | 3 |
-- 10 | {1,3,8,10} | 8 |
-- 11 | {1,3,8,11} | 8 |
#Query 1 : Return 所有 parents for children 11 - {1,3,8,11}。这里的问题是我不知道如何标记11的第一个parent是8.
WITH RECURSIVE c AS (
SELECT 11 AS id
UNION
SELECT t.parent
FROM test AS t
JOIN c ON c.id = t.id
)
SELECT * FROM c;
提前致谢。
你可以携带一个计数器来查看在层次结构中的位置。
WITH RECURSIVE
c
AS
(
SELECT 11 AS id,
0 AS n
UNION ALL
SELECT t.parent,
c.n + 1
FROM test AS t
INNER JOIN c
ON c.id = t.id
)
SELECT *
FROM c
ORDER BY n;
8 在您的示例中将有 1,因此将其指定为第一个父级。
db<>fiddle
编辑:
在此基础上,您可以将锚点集扩展到所有节点。有点不幸的是没有 1 的条目。快速修复是 UNION ALL
也为它创建一条记录(但是你应该通过将记录 (1, NULL)
插入 test
来永久修复此问题.).让第三列携带层次结构开始的实际叶子和最后的GROUP BY
。使用 array_agg()
获取祖先数组。 (过滤 NULL
节点,一旦你将 (1, NULL)
插入到 test
中,这些节点就会在那里。)要获得叶子的直接父级,你可以使用 max()
(或 min()
) 在计数器为 1 的 id 过滤上。
WITH RECURSIVE
c
AS
(
SELECT 1 AS leaf,
1 AS parent,
0 AS n
UNION ALL
SELECT id AS leaf,
id AS parent,
0 AS n
FROM test
UNION ALL
SELECT leaf,
t.parent,
c.n + 1
FROM test AS t
INNER JOIN c
ON c.parent = t.id
)
SELECT leaf AS id,
array_agg(parent ORDER BY n DESC) FILTER (WHERE parent IS NOT NULL) AS ancestry,
max(parent) FILTER (WHERE n = 1) AS parent
FROM c
GROUP BY leaf
ORDER BY leaf;