Cri*_*sta 3 sql postgresql recursion
我有点疯狂地寻找这个问题的解决方案:
我得到了这样的表:
表格数据
我想要一个查询来获取通过条件和所有父项的所有元素,我的意思是,这个结果:
查询结果
我一直在思考查询:
SELECT a.* FROM table a
JOIN table b ON b.id = a.id
WHERE a.id IN (SELECT DISTINCT c.parent_id FROM table c WHERE c.condition = TRUE)
OR b.id IN (SELECT DISTINCT c.id FROM table c WHERE c.condition = TRUE);
Run Code Online (Sandbox Code Playgroud)
但是我只能通过这种方法获得一个级别的差异,我的意思是,没有条件我无法获得超过 1 个父级。非常感谢。
您可以为此使用递归 CTE:
WITH RECURSIVE recCTE AS
(
/*Get all the true children to seed the recursive query*/
SELECT
id,
parent_id,
condition as initial_condition,
1 as depth,
CAST(id as varchar(50)) as path
FROM
table a
WHERE
a.id NOT IN (SELECT DISTINCT parent_id from table)
and a.condition = 'true'
UNION ALL
/*Recursive bit that refers back to itself. Find the parents*/
SELECT
b.id,
b.parent_id,
a.initial_condition,
depth + 1 as depth,
cast(path || '>' || b.id as varchar(50)) as path
FROM
recCTE a
INNER JOIN table b ON
a.parent_id = b.id
WHERE
/*avoid going too deep in case of cycling*/
depth <= 20
)
SELECT * FROM recCTE
Run Code Online (Sandbox Code Playgroud)
递归 CTE 使用两部分:
递归种子:这是 UNION 查询的前半部分。在此,我们确定所有“真”的孩子(ID 不是 Parent_ID)
递归项:这是 UNION 查询的后半部分。它在 FROM 子句中引用回自身 (recCTE) 并table再次加入;将 recCTE.parent_id(以前的迭代 parent_id)链接到表的id. 然后提取该迭代所需的所有信息。
我几乎总是跟踪递归深度(到达该记录需要多少次递归)和路径(从最底部的这个层次结构的其他节点我们击中到达该记录的最底层开始)。
我使用深度来确保我们不会在兔子洞中走得太远。如果您有以下记录:
+----+-----------+
| id | parent_id |
+----+-----------+
| 1 | 5 |
| 5 | 7 |
| 7 | 1 |
+----+-----------+
Run Code Online (Sandbox Code Playgroud)
这将导致无限循环(循环)最坏的情况是它会在深度 20 个循环后停止 (1>5>7>1>5>7>1>5>7>1>5>7>1> 5>7>1>5>7>1>5)。还有其他方法可以停止循环,例如使用路径字段: WHERE a.path NOT LIKE '%' || a.parent_id || '%'例如。
如果需要,您可以通过最终选择变得更漂亮,但这将使您成功完成 95%。