在 Postgresql 中限制基于 FK 的有向无环图的 CTE 搜索
Limiting CTE search based on FK for a Directed Acyclic Graph in Postgresql
我对原始 SQL 还是很陌生,之前在 ORM 中做过所有事情,这可能只需要额外一行 SQL.
在我的 Postgresql 数据库中,我有下表:nodes_table 和 edges_table 是非常标准的表用于在 Postgresql 数据库中定义图形(特别是 DAG)。
我还有一个 edges_group_table,它允许我在逻辑上将一堆边缘组合在一起。例如,如果图形是管道网络,则 edges_group_table 可用于指定哪些边在哪个建筑物中。
我有一个工作通用 Table 表达式 (CTE)(如下所示)来搜索给定节点的祖先节点。
因为图表可能很大,我希望能够减少 CTE 必须搜索的图表部分。除了指定起始节点外,我还希望能够指定一个 group_id 以便将 CTE 搜索限制在指定组中的那些边上。
Tables:
nodes_table
id
name
edges_table
id
name
child_id -- a nodes_table id
parent_id -- a nodes_table id
group_id -- a edges_group_table id
edges_group_table
id
name
如何修改此 CTE 以将图的祖先搜索限制为来自 edges_group_table 的提供组内的那些边?
WITH RECURSIVE graph(id, depth) AS (
SELECT first.parent_id, 1
FROM edges_table AS first
LEFT OUTER JOIN edges_table AS second
ON first.parent_id = second.child_id
WHERE first.child_id = 10 -- the node id we start from
UNION
SELECT DISTINCT parent_id, graph.depth + 1
FROM graph
INNER JOIN edges_table
ON edges_table.child_id = graph.id
)
SELECT id FROM graph
GROUP BY id
ORDER BY MAX(depth) DESC, id ASC
非常感谢对此的任何帮助!
在 CTE 的递归部分和第一个 select 子句中添加 WHERE 子句似乎应该很简单,假设您想限制这两个搜索:
WITH RECURSIVE graph(id, depth) AS (
SELECT first.parent_id, 1
FROM edges_table AS first
LEFT OUTER JOIN edges_table AS second
ON first.parent_id = second.child_id
AND second.group_id = 15 --limit result for second node
WHERE first.child_id = 10 -- the node id we start from
UNION
SELECT DISTINCT parent_id, graph.depth + 1
FROM graph
INNER JOIN edges_table
ON edges_table.child_id = graph.id
WHERE edges_table.group_id = 15 --and all subsequent nodes
)
SELECT id FROM graph
GROUP BY id
ORDER BY MAX(depth) DESC, id ASC
请注意,在第一个表达式中,我们在 LEFT JOIN 部分使用过滤器而不是 WHERE 子句,这样即使第一条边没有连接到第二条边,它也会 return 一行设计的边缘组。
我对原始 SQL 还是很陌生,之前在 ORM 中做过所有事情,这可能只需要额外一行 SQL.
在我的 Postgresql 数据库中,我有下表:nodes_table 和 edges_table 是非常标准的表用于在 Postgresql 数据库中定义图形(特别是 DAG)。
我还有一个 edges_group_table,它允许我在逻辑上将一堆边缘组合在一起。例如,如果图形是管道网络,则 edges_group_table 可用于指定哪些边在哪个建筑物中。
我有一个工作通用 Table 表达式 (CTE)(如下所示)来搜索给定节点的祖先节点。
因为图表可能很大,我希望能够减少 CTE 必须搜索的图表部分。除了指定起始节点外,我还希望能够指定一个 group_id 以便将 CTE 搜索限制在指定组中的那些边上。
Tables:
nodes_table
id
name
edges_table
id
name
child_id -- a nodes_table id
parent_id -- a nodes_table id
group_id -- a edges_group_table id
edges_group_table
id
name
如何修改此 CTE 以将图的祖先搜索限制为来自 edges_group_table 的提供组内的那些边?
WITH RECURSIVE graph(id, depth) AS (
SELECT first.parent_id, 1
FROM edges_table AS first
LEFT OUTER JOIN edges_table AS second
ON first.parent_id = second.child_id
WHERE first.child_id = 10 -- the node id we start from
UNION
SELECT DISTINCT parent_id, graph.depth + 1
FROM graph
INNER JOIN edges_table
ON edges_table.child_id = graph.id
)
SELECT id FROM graph
GROUP BY id
ORDER BY MAX(depth) DESC, id ASC
非常感谢对此的任何帮助!
在 CTE 的递归部分和第一个 select 子句中添加 WHERE 子句似乎应该很简单,假设您想限制这两个搜索:
WITH RECURSIVE graph(id, depth) AS (
SELECT first.parent_id, 1
FROM edges_table AS first
LEFT OUTER JOIN edges_table AS second
ON first.parent_id = second.child_id
AND second.group_id = 15 --limit result for second node
WHERE first.child_id = 10 -- the node id we start from
UNION
SELECT DISTINCT parent_id, graph.depth + 1
FROM graph
INNER JOIN edges_table
ON edges_table.child_id = graph.id
WHERE edges_table.group_id = 15 --and all subsequent nodes
)
SELECT id FROM graph
GROUP BY id
ORDER BY MAX(depth) DESC, id ASC
请注意,在第一个表达式中,我们在 LEFT JOIN 部分使用过滤器而不是 WHERE 子句,这样即使第一条边没有连接到第二条边,它也会 return 一行设计的边缘组。