2013-06-25 203 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。
相關問題