MySQL递归查询方法

1. 前言

最近在做项目时,需要用到mysql递归查询,网上搜索关于递归查询的博客有很多,但是多多少少都有些坑,在这里,自己将它重新整理一下,避免自己踩坑,也方便大家遇到这样的问题。让技术人员能够快速的解决问题。

2. 创建数据库

CREATE DATABASE  IF NOT EXISTS `db_recursive`;
USE `db_recursive`;

-- Table structure for table `t_tree`
DROP TABLE IF EXISTS `t_tree`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `t_tree` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `pid` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

LOCK TABLES `t_tree` WRITE;
INSERT INTO `t_tree` VALUES (1,'江苏省',0),(2,'南京市',1),(3,'栖霞区',2),(4,'江宁区',2),
       (5,'玄武区',2),(6,'徐州市',1),(7,'铜山区',6),(8,'泉山区',6);
UNLOCK TABLES;

3.从上向下递归

3.1.根据单个父节点查询子节点(包括自身)

DROP FUNCTION IF EXISTS `getChildrenBySingleContainSelf`;
delimiter //
CREATE FUNCTION `getChildrenBySingleContainSelf`(rootId INT)
RETURNS varchar(1024)
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempChd VARCHAR(1024);
 
    SET sTemp = '$';
    SET sTempChd = cast(rootId as CHAR);
 
    WHILE sTempChd is not null DO
        SET sTemp = concat(sTemp, ',', sTempChd);
        SELECT group_concat(id) INTO sTempChd FROM  t_tree where FIND_IN_SET(pid, sTempChd) > 0;
    END WHILE;
    RETURN sTemp;
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, `getChildrenBySingleContainSelf`(2));

查询结果如下:
MySQL递归查询方法_第1张图片
现在着重对这个方法做下说明
MySQL递归查询方法_第2张图片

1.getChildrenBySingleContainSelf:方法名;
2.delimiter:使用DECLARE前需要此关键字,不然SQL会报错;
3.rootId:参数
4.id:表主键id字段
5.t_tree:创建的表名
6.pid:上级ID字段

3.2.根据单个父节点查询子节点(不包括自身)

DROP FUNCTION IF EXISTS `getChildrenBySingle`;
delimiter //
CREATE FUNCTION `getChildrenBySingle`(rootId INT)
RETURNS varchar(1024)
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempChd VARCHAR(1024);
 
    SET sTemp = '$';
    SET sTempChd = cast(rootId as CHAR);
 
    WHILE sTempChd is not null DO
        SET sTemp = concat(sTemp, ',', sTempChd);
        SELECT group_concat(id) INTO sTempChd FROM  t_tree where FIND_IN_SET(pid, sTempChd) > 0;
    END WHILE;
    RETURN substr(sTemp, length(rootId) + 4);
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, `getChildrenBySingle`(2));

3.3.根据多个父节点查询子节点(包括自身)

DROP FUNCTION IF EXISTS `getChildrenByMultiContainSelf`;
delimiter //
CREATE FUNCTION `getChildrenByMultiContainSelf`(rootIds VARCHAR(1024))
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempChd VARCHAR(1024);
 
    SET sTemp = '$';
    SET sTempChd = rootIds;
 
    WHILE sTempChd is not null DO
  SET sTemp = concat(sTemp, ',', sTempChd);
        SELECT group_concat(id) INTO sTempChd FROM  t_tree where FIND_IN_SET(pid, sTempChd) > 0;
    END WHILE;
    RETURN sTemp; 
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, `getChildrenByMultiContainSelf`('2,6'));

3.4.根根据多个父节点查询子节点(不包括自身)

DROP FUNCTION IF EXISTS `getChildrenByMulti`;
delimiter //
CREATE FUNCTION `getChildrenByMulti`(rootIds VARCHAR(1024))
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempChd VARCHAR(1024);
 
    SET sTemp = '$';
    SET sTempChd = rootIds;
 
    WHILE sTempChd is not null DO
  SET sTemp = concat(sTemp, ',', sTempChd);
        SELECT group_concat(id) INTO sTempChd FROM  t_tree where FIND_IN_SET(pid, sTempChd) > 0;
    END WHILE;
    RETURN substr(sTemp, length(rootIds) + 4);
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, `getChildrenByMulti`('2,6'));

4.从下向上递归

4.1.根据单个子节点查询父节点(包含自身)

DROP FUNCTION IF EXISTS `getParentBySingleContainSelf`;
delimiter //
CREATE FUNCTION `getParentBySingleContainSelf`(rootId INT)
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempPar VARCHAR(1024);
    
    SET sTemp = '$';
    SET sTempPar = rootId;
 
    WHILE sTempPar is not null DO
        SET sTemp = concat(sTemp, ',', sTempPar);
        SELECT group_concat(pid) INTO sTempPar FROM t_tree where pid <> id and FIND_IN_SET(id, sTempPar) > 0; 
    END WHILE; 
 RETURN sTemp; 
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, getParentBySingleContainSelf(2));

4.2.根据单个子节点查询父节点(不包含自身)

DROP FUNCTION IF EXISTS `getParentBySingle`;
delimiter //
CREATE FUNCTION `getParentBySingle`(rootId INT)
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempPar VARCHAR(1024);
    
    SET sTemp = '$';
    SET sTempPar = rootId; 
 
    WHILE sTempPar is not null DO 
        SET sTemp = concat(sTemp, ',', sTempPar); 
        SELECT group_concat(pid) INTO sTempPar FROM t_tree where pid <> id and FIND_IN_SET(id, sTempPar) > 0; 
    END WHILE; 
 RETURN substr(sTemp, length(rootId) + 4); 
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, getParentBySingle(2));

4.3.根据多个子节点查询父节点(包含自身)

DROP FUNCTION IF EXISTS `getParentByMultiContainSelf`;
delimiter //
CREATE FUNCTION `getParentByMultiContainSelf`(rootIds VARCHAR(1024))
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempPar VARCHAR(1024);
    
    SET sTemp = '$';
    SET sTempPar = rootIds; 
 
    WHILE sTempPar is not null DO 
        SET sTemp = concat(sTemp, ',', sTempPar); 
        SELECT group_concat(pid) INTO sTempPar FROM t_tree where pid <> id and FIND_IN_SET(id, sTempPar) > 0; 
    END WHILE; 
 RETURN sTemp; 
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, getParentByMultiContainSelf('3,7'));

4.4.根据多个子节点查询父节点(不包含自身)

DROP FUNCTION IF EXISTS `getParentByMulti`;
delimiter //
CREATE FUNCTION `getParentByMulti`(rootIds VARCHAR(1024))
RETURNS varchar(1024) 
BEGIN
    DECLARE sTemp VARCHAR(1024);
    DECLARE sTempPar VARCHAR(1024);
    
    SET sTemp = '$';
    SET sTempPar = rootIds; 
 
    WHILE sTempPar is not null DO 
        SET sTemp = concat(sTemp, ',', sTempPar); 
        SELECT group_concat(pid) INTO sTempPar FROM t_tree where pid <> id and FIND_IN_SET(id, sTempPar) > 0; 
    END WHILE; 
 RETURN substr(sTemp, length(rootIds) + 4); 
END;
//

SELECT * FROM t_tree WHERE FIND_IN_SET(id, getParentByMulti('3,7'));

5.注意点

如果在执行创建函数的语句时报如下错误,可以尝试执行以下SQL解决
Error Code: 1418. This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable) 0.000 sec

show VARIABLES like "log_bin_trust_function_creators";
set global log_bin_trust_function_creators = 1;

参考文章

mysql递归查询方法|mysql递归查询遇到的坑,教你们解决办法
Mysql中的递归层次查询(根据父节点查找所有的子节点和根据子节点查询所有的父节点)的两种运用

你可能感兴趣的:(SQL,MySQL)