1. 主页 > 好文章

SQL递归查询子节点方法详:轻松获取多级数据

你有没有遇到过这种情况?当你在处理公司组织架构时,想查某个部门的所有下属单位,结果发现数据像俄罗斯套娃一样层层嵌套?或者在做商品分类管理时,明明知道大类和小类的关系,却不知道怎么一次性提取所有关联数据?别慌,今天咱们就用最直白的大白话,把??SQL递归查询子节点??这个看似高大上的技术,掰开了揉碎了讲给你听。


一、为什么需要递归查询?

举个真实的例子:假设你们公司有100个部门,每个部门下还有子部门,子部门下可能还有小组...现在老板让你统计"技术部"下所有人员名单。如果用普通查询,你得手动查技术部→前端组→后端组→测试组,这得查到猴年马月???递归查询就是帮你自动完成这种"套娃式"查找的神器??。

这里咱们用个更形象的比喻——就像查族谱。你要找张三的所有后代,普通查询只能查到儿子辈,而递归查询能一直查到曾孙、玄孙甚至第N代。


二、递归查询三板斧

??核心原理就三句话??:

  1. 先确定起点(比如从技术部开始)
  2. 顺着父子关系往下找
  3. 找到没有子节点为止

具体怎么操作?咱们用最常见的员工表来演示:

sql复制
员工表结构示例
id | 姓名   | 上级id
1  | 董事长 | null
2  | 总经理 | 1
3  | 技术总监| 2
4  | 前端组长|3
5  | 后端组长|3

??步骤分解??:

  1. ??定锚点??:先锁定要查询的起点,比如技术总监(id=3)
  2. ??建通道??:通过parent_id字段建立上下级关联
  3. ??自动套娃??:让SQL自动重复"查子节点→以子节点为新起点"的过程

三、手把手写递归SQL

这里给出两种最常用的方法,咱们做个对比:

??方法????适用场景????代码复杂度????数据库支持??
WITH RECURSIVEMySQL8.0+/PostgreSQL简单主流推荐
存储过程老版本MySQL复杂需要函数权限

??先说推荐的新方法??(以查找技术总监所有下属为例):

sql复制
WITH RECURSIVE 下属名单 AS (
    -- 第一步:找准起点
    SELECT id,姓名,上级id 
    FROM 员工表 
    WHERE id=3  
    
    UNION ALL
    
    -- 第二步:自动关联子节点
    SELECT e.id,e.姓名,e.上级id
    FROM 员工表 e
    INNER JOIN 下属名单 s ON e.上级id = s.id
)
SELECT * FROM 下属名单;

这段代码就像个智能机器人:

  1. 先抓取id=3的记录
  2. 然后自动查找上级id=3的所有人
  3. 接着把找到的人当作新的"上级",继续找他们的下属
  4. 直到再也找不到新下属为止

??老版本MySQL怎么办???得用存储过程:

sql复制
DELIMITER //
CREATE PROCEDURE 查下属(IN 上级id INT)
BEGIN
    -- 建临时表存结果
    CREATE TEMPORARY TABLE 临时表 (id INT, 姓名 VARCHAR(20));
    
    -- 先插入直接下属
    INSERT INTO 临时表 
    SELECT id,姓名 FROM 员工表 WHERE 上级id=上级id;
    
    -- 循环查子节点
    WHILE EXISTS(SELECT 1 FROM 员工表 WHERE 上级id IN (SELECT id FROM 临时表)) DO
        INSERT INTO 临时表
        SELECT id,姓名 FROM 员工表 
        WHERE 上级id IN (SELECT id FROM 临时表);
    END WHILE;
    
    SELECT * FROM 临时表;
END //
DELIMITER ;

这种方法相当于手动造轮子,虽然能解决问题,但就像用算盘代替计算器——效率低还容易出错。


四、新手必踩的三大坑

??1. 死循环陷阱??
如果数据出现"张三的上级是李四,李四的上级又是张三"这种情况,递归查询就会像驴拉磨一样转圈圈。解决方法很简单——加个计数器:

sql复制
WITH RECURSIVE 下属名单 AS (
    SELECT id,姓名,上级id,1 as 层级 
    FROM 员工表 WHERE id=3  
    UNION ALL
    SELECT e.id,e.姓名,e.上级id,层级+1 
    FROM 员工表 e
    INNER JOIN 下属名单 s ON e.上级id = s.id
    WHERE 层级 < 10 -- 限制最多查10层
)

这样就算数据有问题,最多查10层就停。

??2. 性能黑洞??
当数据量达到十万级时,递归查询可能会让数据库"喘不过气"。这时候要给parent_id字段加索引,就像给高速公路装ETC——能大幅提升通行效率。

??3. 版本兼容性??
特别注意:MySQL5.7及以下版本不支持WITH RECURSIVE!这就好比安卓手机装iOS应用——根本跑不起来。建议先用SELECT VERSION()查数据库版本。


五、常见问题快问快答

??Q:递归查询能查多少层???
A:MySQL默认100层,超过会报错。可通过设置cte_max_recursion_depth参数调整,但一般不建议超过1000层,毕竟谁家公司的层级能深过秦始皇的陵墓?

??Q:能同时查多个起点的下属吗???
A:当然可以!把WHERE条件改成id IN (3,5,7),就像同时打开多个搜索引擎窗口。

??Q:查询结果包含自己吗???
A:这取决于你的初始查询条件。如果起点是技术总监,结果默认包含他本人;如果只想查下级,就把初始条件改成查上级id=3的人。


六、实战技巧锦囊

  1. ??字段优化三原则??:

    • parent_id字段必须建索引
    • 避免在递归查询中使用复杂计算
    • 临时表字段尽量精简
  2. ??调试妙招??:
    在WITH RECURSIVE语句中插入SELECT * FROM 下属名单 WHERE 层级=2,可以查看第二层查询结果,就像给递归过程装了个监控摄像头。

  3. ??替代方案??:
    对于超大数据量(比如百万级),可以考虑改用闭包表设计。这相当于给每个节点预先存储所有子孙关系,虽然占用更多存储空间,但查询速度能提升10倍以上。


小编观点:经过实测,在2023年后的项目中优先推荐使用WITH RECURSIVE方案,既符合SQL标准又便于维护。但如果你接手的是遗留系统,还是得老老实实研究存储过程。记住,递归查询就像吃麻辣火锅——用对了爽翻天,用错了...你懂的。最后送大家一句话:??索引建得好,加班来得少;递归用得巧,升职少不了??。

本文由嘻道妙招独家原创,未经允许,严禁转载