我有一个表答案和多对多表链接(答案n-n答案)
链接有2列:from_id和to_id引用answer_id。 我想通过answer_id(Link中的from_id)获得所有答案的后代。
我写的功能如下:
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()
答案 0 :(得分:1)
我建议您使用递归CTE执行此操作,但您可以在函数中使用相同的方法。
您可以使用数组来跟踪您所处理的所有from_id,然后在下一次运行中忽略结果中已有的from_id的所有记录。在下面的代码中,我使用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;
小提琴: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