Sql Postgres递归函数唯一值

Sql Postgres递归函数唯一值,sql,postgresql,recursion,graph,Sql,Postgresql,Recursion,Graph,我有一个图形结构 Node(pid integer) Neighbor(pid integer, pidn integer) 节点很简单,我应该说邻居为每个节点存储其邻居列表。这是我正在测试的图形(相邻关系的内容): 我想得到一个节点的所有邻居的集合,其度小于一个固定数字,因此我执行以下查询: WITH RECURSIVE search_graph(root, depth) AS ( SELECT n.pidn, 1 FROM node p, neighbor

我有一个图形结构

Node(pid integer)
Neighbor(pid integer, pidn integer)
节点
很简单,我应该说
邻居
为每个节点存储其邻居列表。这是我正在测试的图形(相邻关系的内容):

我想得到一个节点的所有邻居的集合,其度小于一个固定数字,因此我执行以下查询:

WITH RECURSIVE search_graph(root, depth) AS (
        SELECT n.pidn, 1
        FROM node p, neighbor n
        WHERE p.pid = n.pid
        AND p.pid = 1
      UNION
        SELECT nxt.pidn, sg.depth + 1
        FROM neighbor nxt, search_graph sg
        WHERE sg.root = nxt.PID
        AND sg.depth < 3
)
SELECT * FROM search_graph s;
因为它扩展了每个节点的所有子节点,包括访问的子节点:

虽然我想排除访问过的儿童,但制作:

Node | Depth
============
2    | 1
3    | 1
4    | 2
5    | 2
6    | 3

我需要一种方法,仅当节点未被访问时,才能将结果添加到搜索图中。

您是否阅读了有关的Postgresql文档

有一些图形示例,其中一个看起来像是问题的解决方案:

如果链接关系包含循环,则此查询将循环。因为我们需要“深度” 输出,只是将UNIONALL更改为UNION并不能消除循环。相反,我们需要 识别在遵循>链接的特定路径时是否再次到达同一行。我们将两列path和cycle添加到易于循环的查询中:


您是否考虑过查看
ltree
?这可能会帮你省去一点痛苦。另一种可能是,看看你是否可以用GiST索引能够处理的形式对这些数据进行建模。我花了几分钟在这方面,我不认为在递归CTE中能够做到这一点。您需要一种方法来重新访问搜索图递归项(
EXISTS
subquery、left-anti-join等),以排除已访问的节点,并且在递归项上不允许子查询或left-join。也不能使用数组轻松绕过它,因为递归项中不允许使用聚合函数。我认为您必须使用递归SQL或PL/PgSQL函数或在客户机中编写此代码。(详细信息:查看删除的答案)我看不到删除的答案。。。但我仍然在寻找一个解决方案,尽可能地使用任何手段。。。C/PgPLSQL/SQL。。。
Node | Depth
============
2    | 1
3    | 1
1    | 2
3    | 2
4    | 2
5    | 2
2    | 2
2    | 3
3    | 3
1    | 3
4    | 3
5    | 3
6    | 3
0                               1
1               2                               3
2       1    3    4    5                    1       2
3      2 3  1 2  2 6   2                   2 3   1 3 4 5
Node | Depth
============
2    | 1
3    | 1
4    | 2
5    | 2
6    | 3
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
    SELECT g.id, g.link, g.data, 1,
      ARRAY[g.id],
      false
    FROM graph g
  UNION ALL
    SELECT g.id, g.link, g.data, sg.depth + 1,
      path || g.id,
      g.id = ANY(path)
    FROM graph g, search_graph sg
    WHERE g.id = sg.link AND NOT cycle
)
SELECT * FROM search_graph;