postgres中的递归路径查找

recursive path finding in postgres

我 运行 遇到了 Postgres 9.3+ 的问题,我不知何故被困住了。我有以下结构:

任务是将一个特定的对象运行slate成另一个对象(基本上是为了回答像"who belongs this invoice to?"这样的问题)。

对象由 ID 标识,可能的 t运行slations 存储在 table 中,如下所示:

vagrant=# select * from sys_context_translation;
 source_context | target_context | sys_service_id 
----------------+----------------+----------------
              1 |              2 |              1
              3 |              2 |              2
              2 |              1 |              1
              1 |              4 |              1
              4 |              5 |              2
              4 |              2 |              3
(6 rows)

如您所见,有一条从 3 到 5 的路径,如 3 - 2 - 1 - 4 - 5。

我现在需要一个显示该路径的查询。 (因此 source_context 3 为 1 行,2 为下一行,1 为下一行,依此类推...)。我现在有以下查询,但它没有 return 所需的结果:

WITH RECURSIVE translation (source_context, target_context, sys_service_id)
AS
(
  SELECT
    source_context,
    target_context,
    sys_service_id
  FROM sys_context_translation AS s1
  WHERE source_context = 3
  UNION ALL
  SELECT
    s2.source_context,
    s2.target_context,
    s2.sys_service_id
  FROM sys_context_translation AS s2, translation AS t1
  WHERE t1.target_context = s2.source_context
) SELECT *
  FROM translation

;

它做了很多 return,但随后保持 return 行。以下示例限制为 10 行。

 source_context | target_context | sys_service_id 
----------------+----------------+----------------
              3 |              2 |              2 (good one)
              2 |              1 |              1 (good one)
              1 |              2 |              1 (not useful)
              1 |              4 |              1 (good one)
              2 |              1 |              1 (not useful)
              4 |              5 |              2 (good one)
              4 |              2 |              3 (should have stopped a row before)
              1 |              2 |              1 (...)
              2 |              1 |              1
              1 |              4 |              1
(10 rows)

非常感谢任何提示。

你的数据中存在循环(循环依赖),所以你的查询是无止境的。 查询应检查找到的路径是否不包含重复。 您可以通过为路径使用数组来实现此目的。 (我跳过 sys_service_id 不相关)。

with recursive translation (source_context, target_context, path)
as
(
    select
        source_context,
        target_context,
        array[source_context, target_context]
    from sys_context_translation
    where source_context = 3
union all
    select
        s.source_context,
        s.target_context,
        path || s.target_context
    from sys_context_translation as s
    join translation as t
    on t.target_context = s.source_context
    and s.target_context <> all(t.path)
) 
select *
from translation;

 source_context | target_context |    path     
----------------+----------------+-------------
              3 |              2 | {3,2}
              2 |              1 | {3,2,1}
              1 |              4 | {3,2,1,4}
              4 |              5 | {3,2,1,4,5}
(4 rows)