在存储过程中对TreeRelation的递归调用会引发光标错误“已在使用中”

时间:2019-05-22 19:06:52

标签: sql database postgresql plpgsql

我在postgres中创建了一个简单的树关系。父节点可以有n个节点。为了从父节点获取所有子节点,我想编写一个存储过程,以递归方式调用自身。这就是我被困住的地方。

我的想法是,我用父节点调用该过程,然后得到它的所有子节点,并再次为每个子节点调用该过程。递归步骤,即方法的调用,似乎终止了该过程,但我不知道为什么。

代码:

CREATE OR REPLACE PROCEDURE treeDown(INTEGER)
LANGUAGE plpgsql
AS $$
DECLARE
    cur_childs CURSOR FOR select * from TreeRelation where von = $1 AND from < to;
    rec RECORD;
BEGIN
    FOR rec IN cur_childs LOOP
        CALL treeDown(rec.to); -- seems to die here
        RAISE NOTICE '% is a child from %', rec.to, $1;
    end loop;
END;
$$;

错误消息:

  

[42P03]错误:游标“ cur_childs”已在使用中   Wobei:PL / pgSQL   FOR游标SQL语句上的函数treedown(整数)第6行   “ CALL treeDown(rec.nach)” PL / pgSQL函数treedown(integer)第7行   致电

有什么想法吗?我是正确执行调用还是在存储过程中使用另一种方法来调用存储过程?

2 个答案:

答案 0 :(得分:1)

您可以使用匿名游标,而不是命名游标,因此无需重用已经存在的游标。

...
FOR rec IN (SELECT *
                   FROM treerelation
                   WHERE ...) LOOP
...

答案 1 :(得分:0)

我还找到了使用WITH RECURSIVE的可行方法:

-- 3 is our start node in this case
WITH RECURSIVE test(s) AS (
            select to from TreeRelation where from = 3 AND from < to
        UNION
            select to from test, TreeRelation where from = test.s AND from < to
        ) select * from test;

我学到了什么? WITH RECURSIVE始终具有1 non-recursive select1 recursive select。递归选择能够访问临时表test中的数据,该临时表由我们的非递归选择填充。对于从非递归选择(第一个选择)获得的每个条目test,都会调用递归函数(第二个选择)。