方法一:使用 CONNECT BY(传统方式)
-- 假设表名为 my_table,字段为 id 和 parent_id
SELECT id
FROM my_table
START WITH id = '根节点ID'  -- 从根节点开始
CONNECT BY PRIOR id = parent_id  -- 递归条件:父节点的 id = 子节点的 parent_id
MINUS  -- 去重(可选)


-- 或者使用 NOT EXISTS 来筛选叶子节点
SELECT id
FROM my_table t
WHERE NOT EXISTS (
    SELECT 1
    FROM my_table t2
    WHERE t2.parent_id = t.id
)
START WITH id = '根节点ID'
CONNECT BY PRIOR id = parent_id;


方法二:使用 WITH 递归(推荐,更标准)
WITH RECURSIVE cte AS (
    -- 基础查询:从根节点开始
    SELECT id, parent_id, 1 as level
    FROM my_table
    WHERE id = '根节点ID'  -- 替换为实际的根节点ID
    
    UNION ALL
    
    -- 递归查询:查找所有子节点
    SELECT t.id, t.parent_id, c.level + 1
    FROM my_table t
    INNER JOIN cte c ON t.parent_id = c.id
)
-- 筛选叶子节点(没有子节点的节点)
SELECT c.id
FROM cte c
WHERE NOT EXISTS (
    SELECT 1
    FROM my_table t
    WHERE t.parent_id = c.id
);
方法三:一步到位(最简洁)
WITH cte AS (
    SELECT id, parent_id
    FROM my_table
    START WITH id = '根节点ID'
    CONNECT BY PRIOR id = parent_id
)
SELECT id
FROM cte c
WHERE NOT EXISTS (
    SELECT 1 FROM my_table WHERE parent_id = c.id
);
示例
假设数据如下:
id  | parent_id
----|----------
A   | NULL      (根)
B   | A
C   | A
D   | B
E   | B
查询根节点 A 的所有叶子节点:
SELECT id
FROM my_table
START WITH id = 'A'
CONNECT BY PRIOR id = parent_id
MINUS
SELECT id
FROM my_table
WHERE parent_id IS NOT NULL;
结果:C, D, E
性能优化建议
1. 创建索引:
CREATE INDEX idx_parent_id ON my_table(parent_id);
CREATE INDEX idx_id ON my_table(id);
2. 如果数据量大,考虑使用 NO_CYCLE:
START WITH id = '根节点ID'
CONNECT BY NOCYCLE PRIOR id = parent_id

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐