获取SQL树中的所有兄弟姐妹

时间:2014-03-03 05:25:01

标签: sql postgresql common-table-expression hierarchical-data

我必须处理一个表,它是为了适应产品的树形结构而创建的。这样做是为了处理一个产品可以包含多个其他产品的情况(例如,一个产品包含多个其他位置)。因此,我正在制作一个接受OrderDetails的功能,它必须遍历所有产品并列出所列产品的子产品。我正面临一个问题,我必须遍历未知深度的树。请告诉我如何做到这一点。

我已在下表中实现了它,并附带了该功能。但在该解决方案中,列表的深度限制为1,我想要做的是获取树的所有深度。

以下是代码:

CREATE OR REPLACE FUNCTION foo()RETURNS text AS 
$body$
DECLARE _row RECORD;
        _result text := '';
        _child_row RECORD;
        _count integer := -1;
         _marker integer := 1;
BEGIN
    FOR _row IN SELECT * FROM tree_products
    LOOP
        _result := _result || _marker || ' ' || _row.name;
        _count := (SELECT count(product_id) FROM tree_products WHERE parent_id = _row.product_id);
        IF _count > 0 THEN
             FOR _child_row IN SELECT * FROM tree_products WHERE parent_id = _row.product_id
            LOOP
                _result := _result || ' ' || _child_row.name;
            END LOOP;
         END IF;
         _marker := _marker =1;      
    END LOOP;
END;
$body$
    LANGUAGE plpgsql 

UPD使用CTE完成此操作,但发生了分组问题:

CREATE OR REPLACE FUNCTION public.__foo (
)
RETURNS SETOF refcursor AS
$body$
DECLARE _returnvalue refcursor;
        _q text;
 BEGIN
_q :='
        WITH RECURSIVE r_p (product_id, name, parent_id) AS    -- 1
    (SELECT t_p.product_id, t_p.name , t_p.parent_id -- 2
   FROM   tree_products t_p
   WHERE  t_p.product_id = 1
   UNION ALL
   SELECT t_c.product_id, t_c.name, t_c.parent_id    -- 3
   FROM   r_p t_p, tree_products t_c
   WHERE  t_c.parent_id = t_p.product_id)
SELECT product_id, name, parent_id                       -- 4
FROM   r_p;';
OPEN _returnvalue FOR EXECUTE (_q);
RETURN NEXT _returnvalue;
END
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100 ROWS 1000;

我想兄弟姐妹的产品属于他们各自的父母,我想知道怎么写分组声明......

UPD抱歉,tree_products的定义如下:

CREATE TABLE public.tree_products (
  product_id INTEGER DEFAULT nextval('ree_products_product_id_seq'::regclass) NOT NULL,
  name VARCHAR,
  parent_id INTEGER,
  CONSTRAINT ree_products_pkey PRIMARY KEY(product_id)
) 
WITH (oids = false);

UPD:SAMPLE OUTPUT:

product_id | name          | parent_id
---------------------------------------
1          | promo         | NULL
3          | fork          | 1
4          | spoon         | 1
6          | can           | 1
10         | big can       | 3
11         | small can     | 4
12         | large spoon   | 6
13         | mega fork     | 3
14         | super duper   | 6

DESIRED OUTPUT:

product_id | name          | parent_id
---------------------------------------
1          | promo         | NULL
3          | fork          | 1
10         | big can       | 3
13         | mega fork     | 3
4          | spoon         | 1
11         | small can     | 4
6          | can           | 1
12         | large spoon   | 6
14         | super duper   | 6

So, the fetched table has structure of the real tree, like the follwing:
 - promo
   - fork
     - big can
     - mega fork
   - spoon
     - small can
   - can
     - large can
     - super duper

1 个答案:

答案 0 :(得分:2)

This SQLFiddle自上而下遍历树,在数组中保留父行号列表,基本上是“父行位置列表”。

然后按父列表对结果进行排序。

WITH RECURSIVE tree(product_id, name, parentlist) AS (
  SELECT product_id, name, ARRAY[ row_number() OVER (ORDER BY product_id) ]
  FROM tree_products
  WHERE parent_id IS NULL
  UNION
  SELECT tp.product_id, tp.name, array_append(parentlist, row_number() OVER (ORDER BY tp.product_id))
  FROM tree_products tp
  INNER JOIN tree t
  ON (tp.parent_id = t.product_id)
)
SELECT *
FROM tree
ORDER BY parentlist;