2

我必须处理一个表,这是为了适应产品的树结构而创建的。这是为了处理一种产品可以包含多个其他产品(例如,一个包装产品可以包含多个其他位置)的情况。所以,我正在制作一个采用OrderDetails的函数,并且它必须遍历所有产品并列出列出的每个产品的子产品。我面临着一个问题,我必须通过未知深度的树进行迭代。请给我一个想法如何去做。获取SQL树中的所有兄弟姐妹

我已经在下面的表中实现了它,并且列出了它的功能。但在该解决方案中,列表的深度限制为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完成WITH CTE这个usign,但groupiing问题发生:

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; 

我想同级产品是他们respectiveparents下,我不知道如何写分组声明...

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:输出示例:

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 
+0

[链接树视图的GET DATA] [1] [1]:http://stackoverflow.com/questions/21183886/get-hierarchical-data-in-mysql/ 21201379#21201379 它可能对你有用 –

+1

用'WITH RECURSIVE'查询(即递归CTE)这种类型的事情更容易。请参阅http://www.postgresql.org/docs/current/static/queries-with.html。如果您需要更详细的帮助,我强烈建议发布产品表的定义和一些示例数据。 –

+0

@CraigRinger我发现使用[sqlfiddle](http://sqlfiddle.com)对探索数据库查询也很有用。 – hd1

回答

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;