mysql 实现树形的遍历
前言:
关于多级别菜单栏或者权限系统中部门上下级的树形遍历,oracle中有connect by来实现,mysql没有这样的便捷途径,所以MySQL遍历数据表是我们经常会遇到的头痛问题,下面通过存储过程来实现。
1、建立测试表和数据:
DROP TABLE IF EXISTS test.channel;
CREATE TABLE test.channel (
id INT(11) NOT NULL AUTO_INCREMENT,
cname VARCHAR(200) DEFAULT NULL,
parent_id INT(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO channel(id,cname,parent_id)
VALUES (13,'首页',-1),
(14,'TV580',-1),
(15,'生活580',-1),
(16,'左上幻灯片',13),
(17,'帮忙',14),
(18,'栏目简介',17);
2、用临时表和递归过程实现树的遍历(mysql的UDF不能递归调用):
2.1、递归过程输出某节点id路径,类似Oracle SYS_CONNECT_BY_PATH的功能
-- 递归输出某节点id路径
DELIMITER //
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 channel AS t WHERE t.id = nid;
-- 下面这行表示若没有数据返回,程序继续,并将变量done设为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- mysql中可以利用系统参数 max_sp_recursion_depth 来控制递归调用的层数上限。
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 ;
测试:
SET @str='';
CALL pro_cre_pathlist(16,'/',@str);
SELECT @str;
测试结果:

2.2、递归过程输出某节点name路径
-- 递归输出某节点name路径
DELIMITER //
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.cname,delimit,pathstr)
from channel AS t WHERE t.id = nid;
-- 下面这行表示若没有数据返回,程序继续,并将变量done设为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- mysql中可以利用系统参数 max_sp_recursion_depth 来控制递归调用的层数上限。
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 ;
测试:
SET @str='';
CALL pro_cre_pnlist(16,'/',@str);
SELECT @str;
测试结果:

2.3、调用函数输出id路径
-- 调用函数输出id路径
DELIMITER //
DROP FUNCTION IF EXISTS fn_tree_path;
CREATE FUNCTION 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 ;
测试:
SELECT fn_tree_path(16,'/') AS id;
测试结果:
2.4、调用函数输出name路径
-- 调用函数输出name路径
DELIMITER //
DROP FUNCTION IF EXISTS fn_tree_pathname;
CREATE FUNCTION 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 ;
测试:
SELECT fn_tree_pathname(16,'/') AS name;
测试结果:
2.5、调用过程输出子节点
-- 调用过程输出子节点
DELIMITER //
DROP PROCEDURE IF EXISTS pro_show_childlist;
CREATE PROCEDURE pro_show_childlist(IN rootId INT)
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmpList;
CREATE TEMPORARY TABLE IF NOT EXISTS tmpList(
sno INT PRIMARY KEY AUTO_INCREMENT,
id INT,
depth INT); CALL pro_cre_childlist(rootId,0); SELECT channel.id,CONCAT(SPACE(tmpList.depth*2),'--',channel.cname)NAME,
channel.parent_id,tmpList.depth,fn_tree_path(channel.id,'/')path,
fn_tree_pathname(channel.id,'/')pathname FROM tmpList,channel
WHERE tmpList.id=channel.id ORDER BY tmpList.sno;
END // DELIMITER ;
2.6、从某节点向下遍历子节点,递归生成临时表数据
DELIMITER //
DROP PROCEDURE IF EXISTS pro_cre_childlist;
CREATE PROCEDURE 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 channel WHERE parent_id=rootId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET max_sp_recursion_depth=12; INSERT INTO tmpList 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 ;
2.7、调用过程输出父节点
-- 调用过程输出父节点
DELIMITER //
DROP PROCEDURE IF EXISTS pro_show_parentlist;
CREATE PROCEDURE pro_show_parentlist(IN rootId INT)
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmpList;
CREATE TEMPORARY TABLE IF NOT EXISTS tmpList(
sno INT PRIMARY KEY AUTO_INCREMENT,
id INT,
depth INT); CALL pro_cre_parentlist(rootId,0);
SELECT channel.id,CONCAT(SPACE(tmpList.depth*2),'--',channel.cname)NAME,
channel.parent_id,tmpList.depth,fn_tree_path(channel.id,'/')path,
fn_tree_pathname(channel.id,'/')pathname FROM tmpList,channel
WHERE tmpList.id=channel.id ORDER BY tmpList.sno;
END // DELIMITER ;
2.8、从某节点向上追溯根节点,递归生成临时表数据
DELIMITER //
DROP PROCEDURE IF EXISTS pro_cre_parentlist;
CREATE PROCEDURE 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 channel WHERE id=rootId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET max_sp_recursion_depth=12; INSERT INTO tmpList 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 ;
3、开始测试
3.1、从根节点开始显示,显示子节点集合:
CALL pro_show_childlist(-1);
测试结果:

3.2、显示首页下面的子节点
CALL pro_show_childlist(13);
测试结果:

3.3、显示TV580下面的所有子节点
CALL pro_show_childlist(14);
测试结果:

3.4、“帮忙”节点有一个子节点,显示出来:
CALL pro_show_childlist(17);
测试结果:

3.5、“栏目简介”没有子节点,所以只显示最终节点:

3.6、显示“首页”的父节点
CALL pro_show_parentlist(13);
测试结果:

3.7、显示“TV580”的父节点,parent_id为-1
CALL pro_show_parentlist(14);
测试结果:

3.8、显示“帮忙”节点的父节点
CALL pro_show_parentlist(17);
测试结果:

3.9、显示最低层节点“栏目简介”的父节点
CALL pro_show_parentlist(18);
测试结果:

mysql 实现树形的遍历的更多相关文章
- [MySQL] 实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题)
前言: 关于多级别菜单栏或者权限系统中部门上下级的树形遍历,oracle中有connect by来实现,MySQL没有这样的便捷途径,所以MySQL遍历数据表是我们经常会遇到的头痛问题 ...
- mysql存储过程之游标遍历数据表
原文:mysql存储过程之游标遍历数据表 今天写一个mysql存储过程,根据自己的需求要遍历一个数据表,因为对存储过程用的不多,语法不甚熟悉,加之存储过程没有调试环境,花了不少时间才慢慢弄好,故留个痕 ...
- sqlite3树形结构遍历效率对照測试
sqlite3树形结构遍历效率对照測试 一.缘起 项目数据结构:本人从事安防行业,视频监控领域.项目中会遇到监控点位的组织机构划分.暂时划分的巡逻点位等.这些相机点位.连同组织机构,它们在逻辑关系上构 ...
- MySql/Oracle树形结构查询
Oracle树形结构递归查询 在Oracle中,对于树形查询可以使用start with ... connect by select * from treeTable start with id='1 ...
- Mysql实现树形递归查询
最近在做项目迁移,Oracle版本的迁到Mysql版本,遇到有些oracle的函数,mysql并没有,所以就只好想自定义函数或者找到替换函数的方法进行改造. Oracle递归查询 oracle实现递归 ...
- 如何使用mysql存储树形关系
最近遇到业务的一个类似文件系统的存储需求,对于如何在mysql中存储一颗树进行了一些讨论,分享一下,看看有没有更优的解决方案. 一.现有情况 首先,先假设有这么一颗树,一共9个节点,1是root节点, ...
- mysql处理百万数据遍历速度提升(遍历图片名字是否存在)
CREATE DEFINER=`root`@`localhost` FUNCTION `fun_wcmappendix02`(image_name VARCHAR(50)) RETURNS int(1 ...
- MySQL 树节点递归遍历所以子节点
DELIMITER $$ DROP FUNCTION IF EXISTS `getChildList`$$ CREATE FUNCTION `getChildList`(rootId INT) RET ...
- MySQL存储过程-->通过游标遍历和异常处理迁移数据到历史表
-- 大表数据迁移,每天凌晨1点到5点执行,执行间隔时间10分钟,迁移旧数据到历史表. DELIMITER $$ USE `dbx`$$ DROP PROCEDURE IF EXISTS `pro_x ...
随机推荐
- Windows 10 运行原生Bash【Ubuntu】
当前widnows用户的 AppData\Local\lxss 目录下安装了ubuntu,其中rootfs是和ubuntu安装的目录一致 bash进入的就是LINUX的SHELL,因此其二进制格式是E ...
- mysql----JOIN Quiz
JOIN quiz game id mdate stadium team1 team2 1001 8 June 2012 National Stadium, Warsaw POL GRE 1002 8 ...
- Debian, Ubuntu linux安装openjdk
sudo apt-get install openjdk-8-jre 这只是单单安装了jre而已,不要安装这个 安装下面这个就行了 sudo apt-get install openjdk-8-jdk ...
- java使用插件pagehelper在mybatis中实现分页查询
摘要: com.github.pagehelper.PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件 PageHelper是国内牛人的一个开源项目,有兴趣的可以去看源码,都有 ...
- 数据库之mysql篇(1)—— 数据库管理系统简介/mysql的安装、配置
说mysql之前,还是先说说数据库. 什么是数据库: 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后 ...
- c/c++线性队列
线性队列 队列是先进先出,和栈相反. 不循环的队列就是浪费空间,如果tail到了最大值后,即使前面出队了,有空的位置,也不能再入队. seqqueue.h #ifndef __SEQQUEUE__ # ...
- Win10 C盘桌面文件右上方的两个蓝色箭头解决方案
之前看网上有很多桌面蓝色箭头的解决方案,也进行了一些尝试 可是每次Win10系统更新之后蓝色箭头就会重新显示. 最终方案:将建立在桌面的C盘文件移到D盘,桌面创建对应的快捷方式. 一劳永逸,暴力破解.
- IPerf——网络测试工具介绍与源码解析(2)
对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序 ...
- Unity Shader 基础(2) Image Effect
Unity中 Image Effect 是Post Processing的一种方,Unity自身也提供很多Effect效果供使用.Image Effect的使用官方文档做了很多介绍,这里重点Post ...
- Vue编写的todolist小例子
Vue编写的todolist小例子 本篇博客主要包含一个内容: 1.第一个内容:使用Vue编写todolist例子,包含的主要知识是v-model,v-for,el表达式,以及Vue中使用method ...