2013-06-25 217 views
0

假设我有以下表结构:函数返回一个节点的所有子节点的表

| 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; 

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

如果你到目前为止还没有弄清楚,那就是关于邻接表,获得一个节点的所有子节点并将它们打印到一张表中。

有没有人有解决方案?

回答

1

是的。它在PostgreSQL wiki,这是第一次打google

+0

什么是“它”? Postgres维基文章的历史可以追溯到2009年。Google的结果往往过时。 Denis提出的递归CTE要好得多。 –

+0

为什么rCTE解决方案会更好?请解释。 – 2013-06-26 20:23:53

+0

Postgres中的数组处理相对较慢。 PL/pgSQL中的循环和分配相对较慢。递归CTE更短,更简单,可能更快,如果你不仅需要每行ID。并且大部分可移植到其他RDBMS。 –

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; 

(见的的文档示例,以防止图表循环)

3
  • 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; 

这种形式比较快的,因为你不” t填充任何表格(尽管临时表格通常只在RAM中)。

您不需要在PostgreSQL中使用显式游标 - 语句FOR可以做到这一点,它更短,更方便用户使用。

  • 最好的解决方案是丹尼斯的想法 - 使用CTE - 递归SQL。
相关问题