MySQL 根据【父ID】获取【所有子节点】

MySQL根据父节点ID查出所有子节点

测试表

CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` longtext,
  `pid` int(11) DEFAULT NULL,
  `status` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';

SQL

SELECT * 
FROM (
    SELECT
		t1.*,
        IF(FIND_IN_SET(`pid`, @pids) > 0, @pids := CONCAT(@pids, ',', `id`), 0) AS ancestors
    FROM
        ( SELECT * FROM `dept` AS t WHERE t.`status` = 1 ORDER BY t.`id` ASC ) AS t1,
        ( SELECT @pids := 14 ) AS t2
) AS t3
WHERE
	ancestors != 0
	or `id` = 14;

分析

  1. t1:获取所有状态正常的数据并升序排列
  2. t2:初始化@pids变量,它用于获取每条记录时缓存父ID
  3. FIND_IN_SET查询当前记录的父ID@pids中的位置。找不到就返回0
    3.1. 找到就将父id拼接到@pids末尾,以便下一条记录继续在@pids中找自己的父id
  4. 每一条记录都基于前一条执行时得到的@pids进行判断。
  5. 总结:使用此方案的前提是:
    5.1. 所有结点的【id】必需大于【父id】: id > pid。
    5.2. 所有 id 整体是一个升序状态。
    5.3. 如果5.1无法满足,有其他字段能保证查 t1 时,结点可以按【根>干>叶】进行升序排列也行。

用JS生成SQL

var 结果字段 = '*';
var 表名 = '`sys_dept`';
var 主键 = '`id`';
var 父主键 = '`pid`';
var 状态 = '`status`';
var 要查的主键 = 14;
var 包含当前结点 = true;

var sql = `SELECT ${结果字段} 
FROM (
    SELECT
		t1.*,
        IF(FIND_IN_SET(${父主键}, @pids) > 0, @pids := CONCAT(@pids, ',', ${主键}), 0) AS ancestors
    FROM
        ( SELECT * FROM ${表名} AS t WHERE t.${状态} = 1 ORDER BY t.${主键} ASC ) AS t1,
        ( SELECT @pids := ${要查的当前主键} ) AS t2
) AS t3
WHERE
	ancestors != 0
	${包含当前结点 ? `or ${主键} = ${要查的主键}` : ''};`;
console.log(sql);
copy(sql);

参考资料

笑虾:MySQL - 学习笔记 - SELECT语句

博客园 - 张亮java:https://www.cnblogs.com/zhangliang88/p/15910781.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑虾

多情黯叹痴情癫。情癫苦笑多情难

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值