MySQL5.7 实现递归查询

创建测试环境

在线数据库 http://sqlfiddle.com/

1. 创建表

DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept`  (
  `id` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `pid` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

2. 插入测试数据

INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1000', '总公司', NULL);
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1001', '北京分公司', '1000');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1002', '上海分公司', '1000');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1003', '北京研发部', '1001');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1004', '北京财务部', '1001');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1005', '北京市场部', '1001');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1006', '北京研发一部', '1003');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1007', '北京研发二部', '1003');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1008', '北京研发一部一小组', '1006');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1009', '北京研发一部二小组', '1006');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1010', '北京研发二部一小组', '1007');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1011', '北京研发二部二小组', '1007');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1012', '北京市场一部', '1005');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1013', '上海研发部', '1002');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1014', '上海研发一部', '1013');
INSERT INTO `dept`(`id`, `name`, `pid`) VALUES ('1015', '上海研发二部', '1013');
commit;

3. 查看一下刚才插入的数据

select * from dept;

结果如下:

id  |name     |pid |
----+---------+----+
1000|总公司      |    |
1001|北京分公司    |1000|
1002|上海分公司    |1000|
1003|北京研发部    |1001|
1004|北京财务部    |1001|
1005|北京市场部    |1001|
1006|北京研发一部   |1003|
1007|北京研发二部   |1003|
1008|北京研发一部一小组|1006|
1009|北京研发一部二小组|1006|
1010|北京研发二部一小组|1007|
1011|北京研发二部二小组|1007|
1012|北京市场一部   |1005|
1013|上海研发部    |1002|
1014|上海研发一部   |1013|
1015|上海研发二部   |1013|

向上递归

根据一个子节点id,查询所有父节点(包含⾃⾝)

-- 根据一个子节点id,查询所有父节点(包含⾃⾝)
SELECT t2.id, t2.name, t2.pid
 FROM (SELECT @r as _id,
              (SELECT @r := pid FROM dept WHERE id = _id) as pid,
              @l := @l + 1 as lvl
         FROM (SELECT @r := '1014', @l := 0) vars, dept as h
        WHERE @r <> 0) t1
 JOIN dept t2
   ON t1._id = t2.id
ORDER BY T1.lvl DESC; 

代码 @r := 1014 表示查询 id 为 1014 的所有父类

id  |name  |pid |
----+------+----+
1000|总公司   |    |
1002|上海分公司 |1000|
1013|上海研发部 |1002|
1014|上海研发一部|1013|

向下递归

根据⼀个⽗节点查询所有⼦节点(包含⾃⾝)

-- 根据⼀个⽗节点查询所有⼦节点(包含⾃⾝)
SELECT au.id, au.name, au.pid
  FROM (SELECT * FROM dept WHERE pid IS NOT NULL) au,
       (SELECT @pid := '1002') pd
 WHERE FIND_IN_SET(pid, @pid) > 0
   AND @pid := concat(@pid, ',', id)
UNION
SELECT id, name, pid
  FROM dept
 WHERE id = '1002'
 ORDER BY id;  
id  |name  |pid |
----+------+----+
1002|上海分公司 |1000|
1013|上海研发部 |1002|
1014|上海研发一部|1013|
1015|上海研发二部|1013|

根据多个⽗节点查询所有⼦节点(包含⾃⾝)

-- 根据多个⽗节点查询所有⼦节点(包含⾃⾝)
SELECT au.id, au.name, au.pid
  FROM (SELECT * FROM dept WHERE pid IS NOT NULL) au,
       (SELECT @pid := '1002,1005') pd
 WHERE FIND_IN_SET(pid, @pid) > 0 and @pid := concat(@pid, ',', id)
UNION
SELECT id, name, pid
  FROM dept
 WHERE FIND_IN_SET(id, @pid) > 0
 ORDER BY id;  
id  |name  |pid |
----+------+----+
1002|上海分公司 |1000|
1005|北京市场部 |1001|
1012|北京市场一部|1005|
1013|上海研发部 |1002|
1014|上海研发一部|1013|
1015|上海研发二部|1013|

参考
https://www.cnblogs.com/guohu/p/14990788.html
https://wenku.baidu.com/view/6bb57f0e925f804d2b160b4e767f5acfa1c783cf.html?fr=income1-wk_app_search_ctr-search