背景說明
需求:MySQL樹形結構, 根據指定的節點,獲取其下屬的所有子節點(包含路徑上的枝干節點和葉子節點)
枝干節點:如果一個節點下還有子節點,則為枝干節點。
葉子節點:如果一個節點下不再有子節點,則為葉子節點。
問題分析
1、可以使用類似Java這種面向對象的語言,對節點集合進行邏輯處理,獲取所有子節點。
2、直接自定義MySQL函數 getChildList,通過一層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、編寫查詢葉子節點函數 getChildList,如下:
CREATE DEFINER=`root`@`localhost` FUNCTION `getChildList`(`nodeId` int) RETURNS varchar(1000) CHARSET utf8 BEGIN DECLARE childList VARCHAR(1000); # 返回葉子節點結果集 DECLARE tempChild VARCHAR(1000); # 臨時存放子節點 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); # 將返回結果處理,截取掉結果集前面的逗號 END
其中,用到了幾個MySQL的系統函數,如:CAST,CONCAT,GROUP_CONCAT,FIND_IN_SET。
3、調用函數
select getChildList(1) as childList;
0)查詢節點0 的所有子節點:從樹形圖可以看到,應該是 0,1,2,3,11,12,21,22,211,221,222,223,2231,2232
1)查詢節點1 的所有子節點:從樹形圖可以看到,應該是 1,11,12
2)查詢節點2 的所有子節點:從樹形圖可以看到,應該是 2,21,22,211,221,222,223,2231,2232
3)查詢節點3 的所有子節點:從樹形圖可以看到,應該是 3
問題總結
該問題核心點是循環遍歷查找子節點,按照上面的表數據和截圖,閱讀SQL函數,很好理解。
希望能幫到需要幫助的同行,謝謝。
PS:
1)如果需要 根據指定的節點,獲取其下屬的所有葉子節點(只包含葉子節點)。
請參考本人的另一篇博文:https://www.cnblogs.com/miracle-luna/p/10828476.html
2)如果需要 根據指定節點,獲取其所有父節點序列
請參考本人的另一篇博文:https://www.cnblogs.com/miracle-luna/p/10878224.html
3)如果需要 根據指定節點,獲取其所在全路徑節點序列
請參考本人的另一篇博文:https://www.cnblogs.com/miracle-luna/p/10878366.html