You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL:使用WITH RECURSIVE构建条目及其父项列表

嘿,我来帮你搞定这个递归分类的查询问题!首先,你的category表是典型的自关联树形结构,PostgreSQL的WITH RECURSIVE正好用来处理这种层级数据。

先提个小细节:你插入的(6,7,'scary1')这条记录的parent是7,但表里根本没有id=7的分类,所以递归的时候这条记录没法找到父节点,只会显示自身,后面的查询结果里你会看到这一点。

接下来直接上实用的查询,我分几种常见需求说明:

1. 获取每个分类的完整路径(从根节点到当前分类)

这个查询会给每个分类生成一条从顶级父类(比如'animal')到自身的路径,同时显示层级深度:

WITH RECURSIVE category_hierarchy AS (
    -- 非递归部分:先把所有分类作为初始节点,路径初始化为自身,深度0
    SELECT
        id,
        parent,
        name,
        ARRAY[name] AS full_path,
        0 AS depth
    FROM category

    UNION ALL

    -- 递归部分:连接父节点,把父节点的路径和当前分类名拼接,深度+1
    SELECT
        child.id,
        parent.parent,
        child.name,
        parent.full_path || child.name,
        parent.depth + 1
    FROM category child
    JOIN category_hierarchy parent ON child.parent = parent.id
)
-- 最终查询:按分类ID和深度排序,清晰展示层级
SELECT id, name, full_path, depth
FROM category_hierarchy
ORDER BY id, depth DESC;

执行后你会看到:

  • id=4(siamese)的full_path是['animal', 'cat', 'siamese'],depth=2
  • id=6(scary1)的full_path只有['scary1'],因为找不到父节点

2. 获取每个分类的所有父节点列表(从直接父到根)

如果只需要每个分类的父节点集合(不含自身),可以调整递归逻辑:

WITH RECURSIVE parent_list AS (
    -- 非递归部分:先获取每个分类的直接父节点
    SELECT
        child.id AS child_id,
        child.name AS child_name,
        parent.id AS parent_id,
        parent.name AS parent_name,
        ARRAY[parent.name] AS parents
    FROM category child
    LEFT JOIN category parent ON child.parent = parent.id

    UNION ALL

    -- 递归部分:继续向上找父节点的父节点
    SELECT
        pl.child_id,
        pl.child_name,
        grandparent.id,
        grandparent.name,
        pl.parents || grandparent.name
    FROM parent_list pl
    JOIN category grandparent ON pl.parent_id = grandparent.id
)
-- 最终查询:按子分类ID分组,取最长的父节点列表(即完整的父链)
SELECT
    child_id,
    child_name,
    parents
FROM parent_list
WHERE parent_id IS NULL -- 找到根节点的父节点(NULL),此时的parents就是完整父链
OR child_id = 6 -- 单独处理那个没有父节点的分类
ORDER BY child_id;

这个查询会返回:

  • id=4的parents是['cat', 'animal']
  • id=6的parents为NULL(因为找不到父节点)

3. 树形结构展示(缩进区分层级)

如果想直观展示树形结构,用缩进区分层级,可以这样写:

WITH RECURSIVE category_tree AS (
    SELECT
        id,
        parent,
        name,
        0 AS depth
    FROM category
    WHERE parent IS NULL -- 从根节点开始遍历

    UNION ALL

    SELECT
        child.id,
        child.parent,
        child.name,
        parent.depth + 1
    FROM category child
    JOIN category_tree parent ON child.parent = parent.id
)
SELECT
    REPEAT('  ', depth) || name AS tree_view,
    id,
    parent
FROM category_tree
ORDER BY depth, name;

执行后会看到清晰的缩进结构:

animal
  dog
  cat
    siamese
    persian
scary1 -- 因找不到父节点,单独显示

最后再提醒下scary1的记录,它的parent是不存在的id=7,建议要么补上id=7的分类,要么把它的parent改成存在的ID(比如1),这样递归才能正常遍历它的父链。

内容的提问来源于stack exchange,提问作者Nowayz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:16:52