公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
关于多级别菜单栏或者权限系统中部门上下级的树形遍历,oracle中有connect by来实现,MySQL没有这样的便捷途径,所以MySQL遍历数据表是我们经常会遇到的头痛问题,下面通过存储过程来实现。
在开始之前我们先建立测试表和数据,如下:
DROP TABLE IF EXISTS dept; CREATE TABLE dept ( id INT(11) NOT NULL AUTO_INCREMENT, dept_name VARCHAR(200) DEFAULT NULL, parent_id INT(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO dept(id,dept_name,parent_id) VALUES (13,'研发部门',-1), (14,'财务部',-1), (15,'市场部',-1), (16,'研发一部',13), (17,'上海财务组',14), (18,'华东市场业务组',17);
接下来我们可以利用临时表和递归过程实现树的遍历(注意:mysql的UDF不能递归调用)
从某节点向下遍历子节点,递归生成临时表数据
DELIMITER $$ DROP PROCEDURE IF EXISTS xttblog.pro_cre_childlist$$ CREATE PROCEDURE xttblog.pro_cre_childlist(IN rootId INT,IN nDepth INT) BEGIN DECLARE done INT DEFAULT 0; DECLARE b INT; DECLARE cur1 CURSOR FOR SELECT id FROM dept WHERE parent_id=rootId; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; INSERT INTO tmpLst VALUES (NULL,rootId,nDepth); OPEN cur1; FETCH cur1 INTO b; WHILE done=0 DO CALL pro_cre_childlist(b,nDepth+1); FETCH cur1 INTO b; END WHILE; CLOSE cur1; END$$ DELIMITER $$
从某节点向上追溯根节点,递归生成临时表数据
DELIMITER $$ DROP PROCEDURE IF EXISTS xttblog.pro_cre_parentlist$$ CREATE PROCEDURE xttblog.pro_cre_parentlist(IN rootId INT,IN nDepth INT) BEGIN DECLARE done INT DEFAULT 0; DECLARE b INT; DECLARE cur1 CURSOR FOR SELECT parent_id FROM dept WHERE id=rootId; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; INSERT INTO tmpLst VALUES (NULL,rootId,nDepth); OPEN cur1; FETCH cur1 INTO b; WHILE done=0 DO CALL pro_cre_parentlist(b,nDepth+1); FETCH cur1 INTO b; END WHILE; CLOSE cur1; END$$ DELIMITER $$
实现类似Oracle SYS_CONNECT_BY_PATH的功能,递归过程输出某节点id路径
DELIMITER $$ USE db$$ DROP PROCEDURE IF EXISTS pro_cre_pathlist$$ CREATE PROCEDURE pro_cre_pathlist(IN nid INT,IN delimit VARCHAR(10),INOUT pathstr VARCHAR(1000)) BEGIN DECLARE done INT DEFAULT 0; DECLARE parentid INT DEFAULT 0; DECLARE cur1 CURSOR FOR SELECT t.parent_id,CONCAT(CAST(t.parent_id AS CHAR),delimit,pathstr) FROM dept AS t WHERE t.id = nid; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; OPEN cur1; FETCH cur1 INTO parentid,pathstr; WHILE done=0 DO CALL pro_cre_pathlist(parentid,delimit,pathstr); FETCH cur1 INTO parentid,pathstr; END WHILE; CLOSE cur1; END$$ DELIMITER $$
递归过程输出某节点name路径
DELIMITER $$ USE db$$ DROP PROCEDURE IF EXISTS pro_cre_pnlist$$ CREATE PROCEDURE pro_cre_pnlist(IN nid INT,IN delimit VARCHAR(10),INOUT pathstr VARCHAR(1000)) BEGIN DECLARE done INT DEFAULT 0; DECLARE parentid INT DEFAULT 0; DECLARE cur1 CURSOR FOR SELECT t.parent_id,CONCAT(t.dept_name,delimit,pathstr) FROM dept AS t WHERE t.id = nid; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; OPEN cur1; FETCH cur1 INTO parentid,pathstr; WHILE done=0 DO CALL pro_cre_pnlist(parentid,delimit,pathstr); FETCH cur1 INTO parentid,pathstr; END WHILE; CLOSE cur1; END$$ DELIMITER $$
调用函数输出id路径
DELIMITER $$ DROP FUNCTION IF EXISTS db.fn_tree_path$$ CREATE FUNCTION db.fn_tree_path(nid INT,delimit VARCHAR(10)) RETURNS VARCHAR(2000) CHARSET utf8 BEGIN DECLARE pathid VARCHAR(1000); SET @pathid=CAST(nid AS CHAR); CALL pro_cre_pathlist(nid,delimit,@pathid); RETURN @pathid; END$$ DELIMITER $$
调用函数输出name路径
DELIMITER $$ DROP FUNCTION IF EXISTS db.fn_tree_pathname$$ CREATE FUNCTION csdn.fn_tree_pathname(nid INT,delimit VARCHAR(10)) RETURNS VARCHAR(2000) CHARSET utf8 BEGIN DECLARE pathid VARCHAR(1000); SET @pathid=''; CALL pro_cre_pnlist(nid,delimit,@pathid); RETURN @pathid; END$$ DELIMITER $$
调用过程输出子节点
DELIMITER $$ DROP PROCEDURE IF EXISTS pro_show_childLst$$ CREATE PROCEDURE pro_show_childLst(IN rootId INT) BEGIN DROP TEMPORARY TABLE IF EXISTS tmpLst; CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst (sno INT PRIMARY KEY AUTO_INCREMENT,id INT,depth INT); CALL pro_cre_childlist(rootId,0); SELECT d.id,CONCAT(SPACE(tmpLst.depth*2),'--',d.dept_name) NAME,d.parent_id,tmpLst.depth,fn_tree_path(d.id,'/') path,fn_tree_pathname(d.id,'/') pathname FROM tmpLst,dept d WHERE tmpLst.id=d.id ORDER BY tmpLst.sno; END$$ DELIMITER $$
调用过程输出父节点
DELIMITER $$ DROP PROCEDURE IF EXISTS `pro_show_parentLst`$$ CREATE PROCEDURE `pro_show_parentLst`(IN rootId INT) BEGIN DROP TEMPORARY TABLE IF EXISTS tmpLst; CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst (sno INT PRIMARY KEY AUTO_INCREMENT,id INT,depth INT); CALL pro_cre_parentlist(rootId,0); SELECT d.id,CONCAT(SPACE(tmpLst.depth*2),'--',d.dept_name) NAME,d.parent_id,tmpLst.depth,fn_tree_path(d.id,'/') path,fn_tree_pathname(d.id,'/') pathname FROM tmpLst,dept d WHERE tmpLst.id=d.id ORDER BY tmpLst.sno; END$$ DELIMITER $$
参考网址:
http://jan.kneschke.de/projects/mysql/sp/sp_tree.sql
http://blog.csdn.net/ylqmf/article/details/5172901
版权声明:本文为博主原创文章,未经博主允许不得转载。
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » MySQL实现树形的遍历、部门递归、菜单级联