Mysql快速实现递归树状查询
【前言】今天一个好朋友问我的这个问题,以前也没有用到过,恰好有时间,就帮他研究了一下,纯属“现学现卖”,正好在过程中,自己也能学习一下!个人感觉,其实一点也不难,不过是“闻道有先后”,我们是“后”罢了。按照我的习惯,学完东西,总要总结一下嘛,也当做一个备忘录了。
具体需求就不描述了,简而言之,归结为两个:
1.如何通过子节点(cid)加载出所有的父节点(pid)?
2.如何通过父节点(pid)加载出所有的子节点(cid)?
废话不多说,直接上简易教程:
1.创建一个测试表
CREATE TABLE treeNodes ( id INT PRIMARY KEY, nodename VARCHAR(20), pid INT );
2.编写测试数据
INSERT INTO treeNodes VALUES (1,'A',0),(2,'B',1),(3,'C',1), (4,'D',2),(5,'E',2),(6,'F',2), (7,'G',3),(8,'H',6),(9,'I',0), (10,'J',8),(11,'K',8),(12,'L',8), (13,'M',9),(14,'N',12),(15,'O',12), (16,'P',15),(17,'Q',15);
3.实际树型结构
1:A +-- 2:B | +-- 4:D | +-- 5:E | +-- 6:F | | +-- 8:H | | | +-- 10:J | | | +-- 11:K | | | +-- 12:L | | | | +-- 14:N | | | | +-- 15:O | | | | | +-- 16:P | | | | | +-- 17:Q +-- 3:C | +-- 7:G 9:I +-- 13:M
4.创建通过子节点(cid)加载出所有的父节点(pid)的存储函数
DELIMITER // CREATE FUNCTION `getParentList`(rootId INT) RETURNS CHAR(255) BEGIN DECLARE fid INT DEFAULT 1; DECLARE str CHAR(255) DEFAULT rootId; WHILE rootId IS NOT NULL DO SET fid=(SELECT pid FROM treenodes WHERE rootId=id); IF fid > 0 THEN SET str=CONCAT(str,',',fid); SET rootId=fid; ELSE SET rootId=fid; END IF; END WHILE; RETURN str; END //
5.测试(找出id=7的所有父节点)
SELECT getParentList(7); 【结果:7,3,1】
6.创建 通过子节点(cid)加载出所有的父节点(pid)的存储函数
DELIMITER // CREATE FUNCTION `getChildList`(rootId varchar(100)) RETURNS varchar(2000) BEGIN DECLARE str varchar(2000); DECLARE cid varchar(100); SET str = '$'; SET cid = rootId; WHILE cid is not null DO SET str = concat(str, ',', cid); SELECT group_concat(id) INTO cid FROM treeNodes where FIND_IN_SET(pid, cid) > 0; END WHILE; RETURN str; END //
7.测试(找出id=1的所有子节点)
SELECT getChildList(1); 【结果:$,1,2,3,4,5,6,7,8,10,11,12,14,15,16,17】
8.补充:以上一组简单的教程,主要也是总结于网上的各种资料,其实我个人觉得,对于程序员来说“复制,粘贴”没有什么好不耻的,重点是在于:“复制,粘贴”别人的东西后,要学会分析与进一步的思考,并且能够举一反三,最好之后还能认真的总结一下。这样,别人的东西,才变成了你的东西。并且,你可能比之前那个人做的更好;如此下去,才是一个良性循环!
下面我们就简单分析一下这个存储函数的结构:
之后,我又根据朋友的特殊需求,进行了修改,主要是我朋友想查出的并不是各种id,而是希望通过一个子节点的id,直接查出所有父级的名称,便于展示。
DELIMITER // CREATE FUNCTION `getParentList`(rootId VARCHAR(100)) RETURNS VARCHAR(1000) BEGIN DECLARE parentId VARCHAR(100) DEFAULT ''; DECLARE str VARCHAR(1000) DEFAULT ''; DECLARE parentName VARCHAR(100) DEFAULT ''; SET str = (SELECT budget_account_name FROM pms_budget_account WHERE id = rootId); WHILE rootId IS NOT NULL DO SET parentId =(SELECT parent_id FROM pms_budget_account WHERE id = rootId); IF parentId IS NOT NULL THEN SET parentName = (SELECT budget_account_name FROM pms_budget_account WHERE id = parentId); SET str = CONCAT(str, ',', parentName); SET rootId = parentId; ELSE SET rootId = parentId; END IF; END WHILE; RETURN str; END //最后进行测试,达到了朋友想要的预习效果:
至此,才是一个完整的学习过程,也是我常用的学习方式:
碰到难题 ---> 心态放平,不要怕,暗示自己“一定能解决” ---> 各种渠道获取能解决问题的资源(Google/百度,找项目中类似问题参考) ---> 看懂、学会别人的东西 ---> 深度分析,研究其实质性原理(一系列连锁知识的快速串烧) ---> 结合自身实际,进行优化,变成自己的东西; ---> 总结,写出来(使知识更加系统化,回顾加深印象,备忘) |