背景说明
需求:MySQL树形结构, 根据指定的节点,获取其所在全路径节点序列。
问题分析
1、可以使用类似Java这种面向对象的语言,对节点集合进行逻辑处理,获取全路径节点序列。
2、直接自定义MySQL函数 getFullPathNodeList,通过两个while循环,实现对指定节点的所有父节点和所有子节点分别进行查询,最后,将二个查询结果合并,即可得出节点所在全路径节点序列。
功能实现
1、创建数据表
1)表结构截图如下(此处简单建一张表t_tree,id主键自增,uuid表示本节点,parent_uuid表示父节点):
2)建表语句如下:
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50724
Source Host : localhost:3306
Source Schema : test_db
Target Server Type : MySQL
Target Server Version : 50724
File Encoding : 65001
Date: 07/05/2019 21:04:57
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_tree
-- ----------------------------
DROP TABLE IF EXISTS `t_tree`;
CREATE TABLE `t_tree` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`uuid` int(20) NULL DEFAULT NULL,
`parent_uuid` int(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_tree
-- ----------------------------
INSERT INTO `t_tree` VALUES (1, 1, 0);
INSERT INTO `t_tree` VALUES (2, 2, 0);
INSERT INTO `t_tree` VALUES (3, 3, 0);
INSERT INTO `t_tree` VALUES (4, 11, 1);
INSERT INTO `t_tree` VALUES (5, 12, 1);
INSERT INTO `t_tree` VALUES (6, 21, 2);
INSERT INTO `t_tree` VALUES (7, 22, 2);
INSERT INTO `t_tree` VALUES (8, 211, 21);
INSERT INTO `t_tree` VALUES (9, 221, 22);
INSERT INTO `t_tree` VALUES (10, 222, 22);
INSERT INTO `t_tree` VALUES (11, 223, 22);
INSERT INTO `t_tree` VALUES (12, 2231, 223);
INSERT INTO `t_tree` VALUES (13, 2232, 223);
INSERT INTO `t_tree` VALUES (14, 0, );
SET FOREIGN_KEY_CHECKS = 1;
3)表数据结构如下:
4)树形结构如下图:
2、编写查询全路径节点函数 getFullPathNodeList,如下:
CREATE DEFINER=`root`@`localhost` FUNCTION `getFullPathNodeList`(`nodeId` int) RETURNS varchar(1000) CHARSET utf8
BEGIN
################## 声明父序列变量 ###################
DECLARE parentList VARCHAR(1000); # 返回父节点结果集
DECLARE tempParent VARCHAR(1000); # 临时存放父节点
################## 声明子序列变量 ###################
DECLARE childList VARCHAR(1000); # 返回叶子节点结果集
DECLARE tempChild VARCHAR(1000); # 临时存放子节点
################## 查询父节点序列 ###################
SET parentList = '';
SET tempParent = CAST(nodeId as CHAR); # 将int类型转换为String
WHILE tempParent is not null DO # 循环,用于查询节点上所有的父节点
SET parentList = CONCAT(parentList, ',', tempParent); # 存入到返回结果中
SELECT parent_uuid INTO tempParent FROM t_tree where uuid = tempParent; # 查询节点上所有父节点
END WHILE;
#RETURN SUBSTRING(parentList, LENGTH(SUBSTRING_INDEX(parentList, ',', 2)) + 2);
SET parentList = SUBSTRING(parentList, LENGTH(SUBSTRING_INDEX(parentList, ',', 2)) + 2);
################## 查询子节点序列 ###################
SET childList = '';
SET tempChild = CAST(nodeId as CHAR); # 将int类型转换为String
WHILE tempChild is not null DO # 循环,用于查询节点下所有的子节点
SET childList = CONCAT(childList, ',', tempChild); # 存入到返回结果中
SELECT GROUP_CONCAT(uuid) INTO tempChild FROM t_tree where FIND_IN_SET(parent_uuid, tempChild) > 0; # 查询节点下所有子节点
END WHILE;
#RETURN SUBSTRING(childList, 2); # 将返回结果处理,截取掉结果集前面的逗号
SET childList = SUBSTRING(childList, 2);
RETURN CONCAT(parentList, ',' , childList);
END
其中,用到了很多MySQL的系统函数,如:CAST,SUBSTRING,CONCAT,LENGTH,SUBSTRING_INDEX,GROUP_CONCAT,FIND_IN_SET。
3、调用函数
select getFullPathNodeList(1) as fullPathNodeList;
0)查询节点0 所在全路径节点:从树形图可以看到,应该是 ,0,1,2,3,11,12,21,22,211,221,222,223,2231,2232
1)查询节点1 所在全路径节点:从树形图可以看到,应该是 0,1,11,12
2)查询节点223 所在全路径节点:从树形图可以看到,应该是 22,2,0,223,2231,2232
3)查询节点2231 所在全路径节点:从树形图可以看到,应该是 223,22,2,0,2231
问题总结
该问题核心点是把问题拆分成两个循环,分别查找父节点和子节点,按照上面的表数据和截图,阅读SQL函数,很好理解。
希望能帮到需要帮助的同行,谢谢。