1

假设我有以下表结构:

| ID | ParentID | Name |

我想编写一个递归 PostgreSQL 函数来获取节点 ID 的所有子节点作为参数传递给它。

到目前为止,这是我的代码(我只有一部分函数可以获取传递的 ID 的所有子代,现在我需要递归部分):

CREATE OR REPLACE FUNCTION GetAllChildren(IN NodeID INTEGER) RETURNS INTEGER AS $$
DECLARE
    Crs CURSOR FOR SELECT ID, ParentID, Name FROM Tree WHERE ParentID=NodeID;
    VarRow Tree%ROWTYPE;
BEGIN
    OPEN Crs;

    CREATE TEMPORARY TABLE TBL(
        ID SERIAL,
        ParentID INTEGER,
        Name CHARACTER(100)
    );

    LOOP
        FETCH Crs INTO VarRow;
        IF VarRow IS NULL THEN
            EXIT;
        END IF;
        INSERT INTO TBL(ID, ParentID, Name) VALUES(VarRow.ID, VarRow.ParentID, VarRow.Name);
    END LOOP;

    CLOSE Crs;

    RETURN 0;
END;
$$ LANGUAGE plpgsql;

也许最大的问题是我不知道在递归调用之间将输出保存在哪里。

如果到目前为止您还没有弄清楚,那就是邻接列表,获取节点的所有子节点并将它们打印到表中。

有没有人有办法解决吗?

4

2 回答 2

4

有关信息,Postgres 中有常用的表表达式,这可能会有所帮助:

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

改编文档中的示例:

WITH RECURSIVE rec_tree(parent_id, node_id, data, depth) AS (
        SELECT t.parent_id, t.node_id, t.data, 1
        FROM tree t
      UNION ALL
        SELECT t.parent_id, t.node_id, t.data, rt.depth + 1
        FROM tree t, rec_tree rt
        WHERE t.parent_id = rt.node_id
)
SELECT * FROM rec_tree;

(有关防止图形循环的示例,请参阅文档。)

于 2013-06-25T20:01:28.803 回答
4
  • PostgreSQL 不知道本地(过程)受限的临时表——你的临时表在被调用函数的所有实例中都是可见的,它在你的函数之外也可见——它具有会话可见性。

  • 但是 PostgreSQL 函数(PostgreSQL 没有过程)可以直接返回表 - 所以你不需要使用辅助表来存储数据

创建或替换函数 children_by_parent(_parent_id int)
RETURNS SETOF children AS $$ -- children 是表名
声明 r 孩子;
开始
  输入
    从孩子中选择 *
       在哪里 parent_id = _parent_id
  环形
    返回下一个 r; -- 返回节点
    返回查询选择 * FROM children_by_parent(r.id); -- 返回孩子
  结束循环;
  返回;
结尾;
$$ 语言 plpgsql 严格;

这种形式更快,因为您不填写任何表(虽然临时表通常只在 RAM 中)。

您不需要在 PostgreSQL 中使用显式游标 - 语句 FOR 可以完成所有工作,它更短且对用户更友好。

  • 最好的解决方案是 Denis 的想法 - 使用 CTE - 递归 SQL。
于 2013-06-26T07:16:21.313 回答