Function to return a table of all children of a node

╄→尐↘猪︶ㄣ 提交于 2019-12-24 10:45:16

问题


Let's say I've got the following table structure:

| ID | ParentID | Name |

I'd like to write a recursive PostgreSQL function for getting all child nodes of a node ID passed to it as a parameter.

Here's my code so far (I only have one part of the function which gets all the children of the passed ID, and now I need the recursive part):

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;

Perhaps the biggest problem is that I don't know where to save the output between the calls of the recursion.

If you haven't figured out so far, it's about the adjacency list, getting all the children of a node and printing them out to a table.

Does anyone have a solution?


回答1:


Yes. It is there in PostgreSQL wiki, which is first hit on google.




回答2:


For information, there are common table expressions in Postgres, which will probably help here:

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

Adapting the example from the docs:

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;

(See the docs for an example that prevents cycles for a graph.)




回答3:


  • PostgreSQL doesn't know local (procedure) limited temporary tables - your temp table is visible in all instances of called function, and it will be visible outside your function too - it has session visibility.

  • But PostgreSQL functions (PostgreSQL has no procedures) can returns table directly - so you don't need use auxiliary table for storing data

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;

This form is faster, because you don't fill any table (although temp table is usually in RAM only).

You don't need use a explicit cursor in PostgreSQL - statement FOR does all, it is shorter and more user friendly.

  • the best solution is Denis idea - use CTE - recursive SQL.


来源:https://stackoverflow.com/questions/17306314/function-to-return-a-table-of-all-children-of-a-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!