原帖地址 https://github.com/duckdb/duckdb/discussions/15386
通常的递归CTE都是广度优先搜索(BFS)
WITH RECURSIVE
edges(a, b) as(
VALUES
(1, 2),
(1, 3),
(2, 4),
(4, 5),
(4, 6)
),
bfs(node, path) AS (
SELECT 1 AS node, [] :: STRUCT("from" INT, "to" INT)[] AS path -- Start with node 1 (root)
UNION ALL
SELECT e.b, bft.path|| [{'from': bft.node, 'to': e.b}]
FROM bfs AS bft,
edges AS e
WHERE bft.node = e.a
)
SELECT * FROM bfs;
┌───────┬────────────────────────────────────────────────────────────────────┐
│ node │ path │
│ int32 │ struct("from" integer, "to" integer)[] │
├───────┼────────────────────────────────────────────────────────────────────┤
│ 1 │ [] │
│ 2 │ [{'from': 1, 'to': 2}] │
│ 3 │ [{'from': 1, 'to': 3}] │
│ 4 │ [{'from': 1, 'to': 2}, {'from': 2, 'to': 4}] │
│ 5 │ [{'from': 1, 'to': 2}, {'from': 2, 'to': 4}, {'from': 4, 'to': 5}] │
│ 6 │ [{'from': 1, 'to': 2}, {'from': 2, 'to': 4}, {'from': 4, 'to': 6}] │
└───────┴────────────────────────────────────────────────────────────────────┘
DuckDB CTE模块的设计者kryonix提供了如下技巧提供DFS,但是还有问题,没有求出全部路径。
WITH RECURSIVE
edges(a, b) as(
VALUES
(1, 2),
(1, 3),
(2, 4),
(4, 5),
(4, 6)
),
dfs(stack, path) AS (
SELECT [1] AS stack, [] :: STRUCT("from" INT, "to" INT)[] AS path -- Start with node 1 (root)
UNION ALL
(WITH siblings AS (
SELECT ARRAY_AGG(e.b ORDER BY e.b ASC) AS siblings
-- ^^^
-- This determines the order of traversal of the siblings
FROM dfs AS dft,
edges AS e
WHERE dft.stack[1] = e.a
)
SELECT x.*
FROM siblings AS _(s), LATERAL
(SELECT s || dft.stack[2:] AS stack, -- Push the stack
dft.path || [{'from': dft.stack[1], 'to': s[1]}] AS path -- Add the edge to the path
FROM dfs AS dft
WHERE array_length(s) > 0 -- There are more siblings to traverse
UNION ALL
SELECT dft.stack[2:], -- Pop the stack
[] :: STRUCT("from" INT, "to" INT)[] AS path -- Reset the path
FROM dfs AS dft
WHERE array_length(s) IS NULL AND dft.stack <> [] -- No more siblings to traverse
) AS x
)
)
SELECT * FROM dfs;
┌───────────┬────────────────────────────────────────────────────────────────────┐
│ stack │ path │
│ int32[] │ struct("from" integer, "to" integer)[] │
├───────────┼────────────────────────────────────────────────────────────────────┤
│ [1] │ [] │
│ [2, 3] │ [{'from': 1, 'to': 2}] │
│ [4, 3] │ [{'from': 1, 'to': 2}, {'from': 2, 'to': 4}] │
│ [5, 6, 3] │ [{'from': 1, 'to': 2}, {'from': 2, 'to': 4}, {'from': 4, 'to': 5}] │
│ [6, 3] │ [] │
│ [3] │ [] │
│ [] │ [] │
└───────────┴────────────────────────────────────────────────────────────────────┘

228

被折叠的 条评论
为什么被折叠?



