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

PostgreSQL中能否编写自下而上的递归CTE查询上级区域?

用自下而上的递归CTE查询特定区域的所有上级区域

首先是我们使用的territories表结构:

CREATE TABLE territories 
(
    id serial PRIMARY KEY,
    name varchar NOT NULL,
    containing_id int
);

CREATE INDEX container_id_index ON territories (containing_id);

示例数据如下:

INSERT INTO territories (id, name, containing_id)
VALUES
    (1, 'Earth', NULL),
    (2, 'North America', 1),
    (3, 'South America', 1),
    (4, 'Africa', 1),
    (5, 'Asia', 1),
    (6, 'United States', 2),
    (7, 'Canada', 2),
    (8, 'Mexico', 2),
    (10, 'Georgia', 6),
    (11, 'Atlanta', 10),
    (12, 'Nigeria', 4),
    (13, 'Abuja', 12),
    (14, 'Chile', 3),
    (15, 'Santiago', 14),
    (16, 'Ontario', 7),
    (17, 'Toronto', 16),
    (19, 'Cambodia', 5),
    (20, 'Phnom Penh', 19);

已经可以通过自上而下的递归CTE列出指定起点下的所有子区域,比如以“Earth”为起点的查询:

-- 自上而下查询
WITH RECURSIVE superterritories AS 
(
    SELECT
        id,
        containing_id,
        name,
        NULL::varchar AS superterritory_name
    FROM
        territories
    WHERE
        name = 'Earth'
    UNION
    SELECT
        t.id,
        t.containing_id,
        t.name,
        sup.name AS superterritory_name
    FROM
        territories t
    INNER JOIN 
        superterritories sup ON sup.id = t.containing_id
)
SELECT
    *
FROM
    superterritories;

查询输出:

id | containing_id |     name      | superterritory_name
----+---------------+---------------+-----------------
  1 |        [NULL] | Earth         | [NULL]
  2 |             1 | North America | Earth
  3 |             1 | South America | Earth
  4 |             1 | Africa        | Earth
  5 |             1 | Asia          | Earth
  6 |             2 | United States | North America
  7 |             2 | Canada        | North America
  8 |             2 | Mexico        | North America
 12 |             4 | Nigeria       | Africa
 14 |             3 | Chile         | South America
 19 |             5 | Cambodia      | Asia
 10 |             6 | Georgia       | United States
 13 |            12 | Abuja         | Nigeria
 15 |            14 | Santiago      | Chile
 16 |             7 | Ontario       | Canada
 20 |            19 | Phnom Penh    | Cambodia
 11 |            10 | Atlanta       | Georgia
 17 |            16 | Toronto       | Ontario
(18 rows)

如果将WHERE条件改为name = 'United States',输出结果为:

id | containing_id |     name      | superterritory_name
----+---------------+---------------+-----------------
  6 |             2 | United States | [NULL]
 10 |             6 | Georgia       | United States
 11 |            10 | Atlanta       | Georgia

自下而上的递归CTE实现

当然可以编写自下而上的递归CTE,用来列出特定区域的所有上级区域。核心思路是从目标区域开始,不断向上关联containing_id对应的父区域,直到没有上级(containing_id为NULL)为止。

以下是实现代码,以查询“Atlanta”的所有上级区域为例:

-- 自下而上查询
WITH RECURSIVE sub_territories AS
(
    -- 初始查询:获取目标区域
    SELECT
        id,
        containing_id,
        name,
        NULL::varchar AS sub_territory_name
    FROM territories
    WHERE name = 'Atlanta'
    UNION
    -- 递归部分:关联父区域
    SELECT
        t.id,
        t.containing_id,
        t.name,
        sub.name AS sub_territory_name
    FROM territories t
    INNER JOIN sub_territories sub ON t.id = sub.containing_id
)
SELECT * FROM sub_territories;

查询输出

执行上述查询后,会得到Atlanta的所有上级区域,结果如下:

id | containing_id |     name      | sub_territory_name
----+---------------+---------------+-------------------
 11 |            10 | Atlanta       | [NULL]
 10 |             6 | Georgia       | Atlanta
  6 |             2 | United States | Georgia
  2 |             1 | North America | United States
  1 |        [NULL] | Earth         | North America
(5 rows)

你可以修改初始查询中的WHERE name = 'Atlanta'条件,替换为任意区域名称,来获取对应区域的所有上级层级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:15:01