PostgreSQL Hierarchical,类别树

时间:2012-08-06 19:24:45

标签: php postgresql postgresql-8.4 hierarchical-trees hierarchical-query

ENV:postgresql-8.4

我正在尝试构建一个类别树。基本上我期待最终输出如下:   

categoryName 
categoryPath
leafcategory
例如:

Digital Camera
Electronics ::: Digital Camera 
true

表格结构是

CREATE TABLE categories (
    id  SERIAL PRIMARY KEY,
    categoryid bigint,
    categoryparentid bigint,
    categoryname text,
    status integer DEFAULT 0,
    lang text,
    eysiteid text,
    country text,
    tempid text,
    leafcategory boolean
);

到目前为止,我已经得到了这个但是没有用。任何帮助将受到高度赞赏:

WITH RECURSIVE tree (CategoryID, CategoryParentID, CategoryName, category_tree, depth) 
AS ( 
    SELECT 
        CategoryID,
        CategoryParentID,
        CategoryName,
        CategoryName AS category_tree,
        0 AS depth 
    FROM categories 
    WHERE CategoryParentID IS NULL 
UNION ALL 
    SELECT 
        c.CategoryID,
        c.CategoryParentID,
        c.CategoryName,
        tree.category_tree  || '/' || c.CategoryName AS category_tree,
        depth+1 AS depth 
    FROM tree 
        JOIN categories c ON (tree.category_tree  = c.CategoryParentID) 
) 
SELECT * FROM tree ORDER BY category_tree;

来自数据库的样本

cat=> select * from categories;
  id   | categoryid | categoryparentid |          categoryname          | status | lang | eysiteid | country | tempid | leafcategory 
-------+------------+------------------+--------------------------------+--------+------+------------+---------+--------+--------------
     1 |         -1 |                0 | Root                           |      1 | en   | 0          | us      |        | f
     2 |      20081 |               -1 | Antiques                       |      1 | en   | 0          | us      |        | f
    17 |       1217 |            20081 | Primitives                     |      0 | en   | 0          | us      |        | t
    23 |      22608 |            20081 | Reproduction Antiques          |      0 | en   | 0          | us      |        | t
    24 |         12 |            20081 | Other                          |      0 | en   | 0          | us      |        | t
    25 |        550 |               -1 | Art                            |      1 | en   | 0          | us      |        | f
    29 |       2984 |               -1 | Baby                           |      1 | en   | 0          | us      |        | f

2 个答案:

答案 0 :(得分:2)

看来你正在加入错误的领域。

 --  create some test data
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE categories
    -- ( id  SERIAL PRIMARY KEY
    ( categoryid SERIAL PRIMARY KEY
    , categoryparentid bigint REFERENCES categories(categoryid)
    , categoryname text
    -- , status integer DEFAULT 0
    -- , lang text
    -- , ebaysiteid text
    -- , country text
    -- , tempid text
    -- , leafcategory boolean
        );
INSERT INTO categories(categoryid,categoryparentid) SELECT gs, 1+(gs/6)::integer
FROM generate_series(1,50) gs;

UPDATE categories SET categoryname = 'Name_' || categoryid::text;
UPDATE categories SET categoryparentid = NULL WHERE categoryparentid <= 0;
UPDATE categories SET categoryparentid = NULL WHERE categoryparentid  >= categoryid;


WITH RECURSIVE tree (categoryid, categoryparentid, categoryname, category_tree, depth)
AS (
    SELECT
        categoryid
        , categoryparentid
        , categoryname
        , categoryname AS category_tree
        , 0 AS depth
    FROM categories
    WHERE categoryparentid IS NULL
UNION ALL
    SELECT
        c.categoryid
        , c.categoryparentid
        , c.categoryname
        , tree.category_tree  || '/' || c.categoryname AS category_tree
        , depth+1 AS depth
    FROM tree
        JOIN categories c ON tree.categoryid  = c.categoryparentid
    )
SELECT * FROM tree ORDER BY category_tree;
编辑:递归的另一种(“非功能”)符号似乎更好用:

WITH RECURSIVE tree AS (
    SELECT
        categoryparentid AS parent
        , categoryid AS self
        , categoryname AS treepath
        , 0 AS depth
    FROM categories
    WHERE categoryparentid IS NULL
UNION ALL
    SELECT
        c.categoryparentid AS parent
        , c.categoryid AS self
        , t.treepath  || '/' || c.categoryname AS treepath
        , depth+1 AS depth
    FROM categories c
    JOIN tree t ON t.self  = c.categoryparentid
    )
SELECT * FROM tree ORDER BY parent,self
   ;

更新:在原始查询中,您应该替换

WHERE CategoryParentID IS NULL

由:

WHERE CategoryParentID = 0

或者甚至可能:

WHERE COALESCE(CategoryParentID, 0) = 0

答案 1 :(得分:0)

看看this gist它或多或少是你想要做的。在你的情况下,我最好使用LTree materialized path Postgresql's extension