【问题标题】:PostgreSQL Hierarchical, category treePostgreSQL 分层,类别树
【发布时间】:2012-08-03 19:06:01
【问题描述】:

环境:postgresql-8.4

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

分类名称 类别路径 叶类 例如: 数码相机 电子产品 ::: 数码相机 真的

表结构是

创建表类别( id 序列主键, 分类号 bigint, categoryparentid bigint, 类别名称文本, 状态整数 DEFAULT 0, 朗文字, eysiteid 文本, 国家文本, 温文尔雅的文字, 叶类别布尔值 );

到目前为止,我已经得到了这个,但没有工作。任何帮助将不胜感激:

WITH RECURSIVE 树(CategoryID、CategoryParentID、CategoryName、category_tree、depth) 作为 ( 选择 类别ID, 类别父 ID, 分类名称, 类别名称 AS 类别树, 0 AS 深度 从类别 其中 CategoryParentID 为 NULL 联合所有 选择 c.CategoryID, c.CategoryParentID, c.类别名称, 树.category_tree || '/' || c.CategoryName AS category_tree, depth+1 AS 深度 从树 加入类别 c ON (tree.category_tree = c.CategoryParentID) ) SELECT * FROM tree ORDER BY category_tree;

来自数据库的样本

cat=> 从类别中选择 *; 编号 |类别ID |类别父ID |类别名称 |状态 |朗 | eysiteid |国家 |胆小|叶类 --------+------------+------------------+------------ ----------+--------+------+------------ -+---------+--------+-------------- 1 | -1 | 0 |根 | 1 | zh | 0 |我们 | | F 2 | 20081 | -1 |古董 | 1 | zh | 0 |我们 | | F 17 |第1217章20081 |原语 | 0 | zh | 0 |我们 | |吨 23 | 22608 | 20081 |复制古董 | 0 | zh | 0 |我们 | |吨 24 | 12 | 20081 |其他 | 0 | zh | 0 |我们 | |吨 25 | 550 | -1 |艺术 | 1 | zh | 0 |我们 | | F 29 | 2984 | -1 |宝贝 | 1 | zh | 0 |我们 | | F

【问题讨论】:

  • 您有一种奇怪的方式来标记树的根节点(通常,根节点的父指针为 NULL)。查看我的更新。

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


【解决方案1】:

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

【讨论】:

    【解决方案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
    

    【讨论】:

    • 必须提到根类别的 categoryparentid 为 0 。
    • 您必须将 parent 设置为 NULL where parent
    • 我找不到实际的错误;如果我使用“功能”符号,则递归在此处失败(第 9.1.2 页)。
    • 我认为 parent 不能为空,因为类型是 bigint。我应该将 categoryparentid 类型更改为 text 吗?
    • 绝对不是。 bigint 类型应该可以为空(默认情况下),就像整数类型或任何其他类型一样。顺便说一句:看来您已经有太多候选键了。 ID 字段的用途是什么?
    猜你喜欢
    • 1970-01-01
    • 2020-02-03
    • 2021-02-25
    • 1970-01-01
    • 2020-07-09
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多