前言:
关于多级别菜单栏或者权限系统中部门上下级的树形遍历,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 实现树形的遍历的更多相关文章

  1. [MySQL] 实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题)

    前言:         关于多级别菜单栏或者权限系统中部门上下级的树形遍历,oracle中有connect by来实现,MySQL没有这样的便捷途径,所以MySQL遍历数据表是我们经常会遇到的头痛问题 ...

  2. mysql存储过程之游标遍历数据表

    原文:mysql存储过程之游标遍历数据表 今天写一个mysql存储过程,根据自己的需求要遍历一个数据表,因为对存储过程用的不多,语法不甚熟悉,加之存储过程没有调试环境,花了不少时间才慢慢弄好,故留个痕 ...

  3. sqlite3树形结构遍历效率对照測试

    sqlite3树形结构遍历效率对照測试 一.缘起 项目数据结构:本人从事安防行业,视频监控领域.项目中会遇到监控点位的组织机构划分.暂时划分的巡逻点位等.这些相机点位.连同组织机构,它们在逻辑关系上构 ...

  4. MySql/Oracle树形结构查询

    Oracle树形结构递归查询 在Oracle中,对于树形查询可以使用start with ... connect by select * from treeTable start with id='1 ...

  5. Mysql实现树形递归查询

    最近在做项目迁移,Oracle版本的迁到Mysql版本,遇到有些oracle的函数,mysql并没有,所以就只好想自定义函数或者找到替换函数的方法进行改造. Oracle递归查询 oracle实现递归 ...

  6. 如何使用mysql存储树形关系

    最近遇到业务的一个类似文件系统的存储需求,对于如何在mysql中存储一颗树进行了一些讨论,分享一下,看看有没有更优的解决方案. 一.现有情况 首先,先假设有这么一颗树,一共9个节点,1是root节点, ...

  7. mysql处理百万数据遍历速度提升(遍历图片名字是否存在)

    CREATE DEFINER=`root`@`localhost` FUNCTION `fun_wcmappendix02`(image_name VARCHAR(50)) RETURNS int(1 ...

  8. MySQL 树节点递归遍历所以子节点

    DELIMITER $$ DROP FUNCTION IF EXISTS `getChildList`$$ CREATE FUNCTION `getChildList`(rootId INT) RET ...

  9. MySQL存储过程-->通过游标遍历和异常处理迁移数据到历史表

    -- 大表数据迁移,每天凌晨1点到5点执行,执行间隔时间10分钟,迁移旧数据到历史表. DELIMITER $$ USE `dbx`$$ DROP PROCEDURE IF EXISTS `pro_x ...

随机推荐

  1. html之input标签(11)

    1.输入框 type=“text” 就是一个简单的输入框 <body> <input type="text"> </body> 2.密码输入框 ...

  2. 如何用ABP框架快速完成项目(9) - 用ABP一个人快速完成项目(5) - 不要执着于设计模式和DDD理论,避免原教旨主义

    为什么要写这节文章呢?   首先主动看我这系列文章和参加活动课程的同学, 肯定是积极好学的. 所以很大概率是学过设计模式和DDD理论的. 很大概率不是走一点都不懂设计模式和DDD理论这个极端, 而是走 ...

  3. Android 程序崩溃之后fragment出现画面重叠问题

    1.解决方法: 直接在包含Fragment的Activity中复写onSaveInstanceState()方法,使其空实现 @Override protected void onSaveInstan ...

  4. BitnamiRedmine配置邮件系统备忘

    前几天安装的Redmine邮件系统存在问题,需要换一个,方法记录如下: 修改配置文件: cd ~/redmine/apps/redmine/htdocs/config vi configuration ...

  5. 智能POS删除文件和数据库操作步骤

    1. 2. 3. 4.winbox:日志:winboxcash:数据库:winboxcyb:其他文件: 5.删除以上三个文件夹

  6. C#-运算符(四)

    算术运算符 +:两个操作数相加,例:2+3得5 -:第一个操作数减去第二个操作数 例:5-3得2 *:两个操作数相乘,例:2*3得6 /:分子除以分母,例:5/2得2 %:取模运算符,整除后的余数,例 ...

  7. 深入理解C语言内存管理

    之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少. 问题不能拖,我这就来学习一下吧,争取一次搞定. 在任何程序设计环境及 ...

  8. linux局域网搭建yum仓库(本地(file)、网络(ftp、http))

    linux局域网搭建yum仓库(本地(file).网络(ftp.http)) yum配置文件解释: [ ]:定义仓库,base为仓库的名字,可任意 name:仓库的简短文字描述 baseurl:仓库的 ...

  9. Linux 小知识翻译 - 「SCP和SFTP」

    这次想说说「SCP和SFTP」. 不管SCP还是SFTP,都是SSH的功能之一.都是使用SSH协议来传输文件的. 不用说文件内容,就是登录时的用户信息都是经过SSH加密后才传输的,所以说SCP和SFT ...

  10. March 01st, 2018 Week 9th Thursday

    Let bygones be bygones. 过去的就让它过去吧. What happened has happened, it cannot be undone, so just leave it ...