函数返回节点的所有子节点的表

时间:2013-06-25 19:54:12

标签: function postgresql recursion plpgsql children

假设我有以下表结构:

| ID | ParentID |姓名|

我想编写一个递归的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;

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

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

有没有人有解决方案?

3 个答案:

答案 0 :(得分: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;

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

答案 1 :(得分:4)

  • PostgreSQL不知道本地(程序)有限的临时表 - 你的临时表在所有被调用函数的实例中都是可见的,它也会在你的函数外面显示 - 它具有会话可见性。

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

CREATE OR REPLACE FUNCTION children_by_parent(_parent_id int)
RETURNS SETOF children AS $$ -- children is table name
DECLARE r children;
BEGIN
  FOR r IN 
    SELECT * FROM children
       WHERE parent_id = _parent_id
  LOOP
    RETURN NEXT r; -- return node
    RETURN QUERY SELECT * FROM children_by_parent(r.id); -- return children
  END LOOP;
  RETURN;
END;
$$ LANGUAGE plpgsql STRICT;

这个表单更快,因为你没有填充任何表格(虽然临时表通常只在RAM中)。

你不需要在PostgreSQL中使用显式游标 - 语句FOR do all,它更短,更友好。

  • 最好的解决方案是Denis的想法 - 使用CTE - 递归SQL。

答案 2 :(得分:0)

是。它位于PostgreSQL wiki,首先在google上点击。