Postgresql中的无限递归函数异常

Infinity recursive function exception in Postgresql

我有一个 table 答案和多对多 table Link(答案 n-n 答案)

Link 有 2 列:from_id 和 to_id 对 answer_id 的引用。 我想通过 answer_id ( from_id in Link )获得答案的所有后代。

我写的函数如下:

CREATE OR REPLACE FUNCTION getAllChild(_answer_id BIGINT)
RETURNS SETOF BIGINT AS $$
DECLARE r link;
BEGIN
  FOR r IN 
    SELECT * FROM link
       WHERE from_id = _answer_id
  LOOP
    RETURN NEXT r.to_id;
    RETURN QUERY SELECT * FROM getAllChild(r.to_id);
  END LOOP;
  RETURN;
END;
$$ LANGUAGE plpgsql STRICT;

SELECT * FROM getAllChild(1);

如果 to_id 不与已经得到的 from_id 重复,结果很好,否则我将得到递归无穷大。

我的问题是如何使循环跳过现有的 to_id 以在 RETURN QUERY

中调用 getAllChild()

我建议您使用递归 CTE 执行此操作,不过您可以在函数中使用相同的方法。

您可以使用数组来跟踪您处理过的所有 from_id,然后在接下来的 运行 中忽略 [=28= 的任何记录] 已经在结果中。在下面的代码中,我使用 path 数组来跟踪所有已经看到的 from_id。

with recursive t as
(
  select l.from_id,l.to_id, ARRAY[l.from_id] as path, 1 as depth 
  from link l where from_id = 2
union all 
  select l.from_id,l.to_id, array_append(t.path,l.from_id), t.depth+1 
  from link l 
  inner join t on l.from_id = t.to_id
  where not (l.from_id = ANY (t.path))  -- ignore records already processed
)
select * from t;

Fiddle 在:http://sqlfiddle.com/#!15/024e80/1

更新:作为函数

CREATE OR REPLACE FUNCTION getAllChild(_answer_id BIGINT)
RETURNS SETOF BIGINT AS $$
BEGIN
  return query 
    with recursive t as
    (
    select l.from_id,l.to_id, ARRAY[l.from_id] as path, 1 as depth from link l where from_id = _answer_id
    union all 
    select l.from_id,l.to_id, array_append(t.path,l.from_id), t.depth+1 from link l 
    inner join t on l.from_id = t.to_id
    where not (l.from_id = ANY (t.path))
    )
    select to_id from t;
END;
$$ LANGUAGE plpgsql STRICT;

数组文档:https://www.postgresql.org/docs/current/static/arrays.html

CTE:https://www.postgresql.org/docs/current/static/queries-with.html