前言:
关于多级别菜单栏或者权限系统中部门上下级的树形遍历,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. 2018-11-16 中文代码示例之Programming in Scala笔记第四五六章

    续前文: 中文代码示例之Programming in Scala学习笔记第二三章. 同样仅节选有意思的例程部分作演示之用. 源文档仍在: program-in-chinese/Programming_ ...

  2. 【代码笔记】Web-JavaScript-JavaScript 条件语句

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  3. Android开发CheckBox控件,全选,反选,取消全选

    在Android开发中我们经常会使用CheckBox控件,那么怎么实现CheckBox控件的全选,反选呢 首先布局我们的界面: <?xml version="1.0" enc ...

  4. listview reclyerview上下拉刷新

    x写控件挺麻烦的,因为有很多细节要处理好,列表控件使用太频繁了,网上也各种自定义的方法,一般的listview自定义肯定会联想到加个头部,然后监听事件加动画,其实方式很多种,今天记录的方式是另外一种方 ...

  5. 直接通过Binder的onTransact完成跨进程通信

    1.具体代码: 服务端实现: public class IPCService extends Service { private static final String DESCRIPTOR = &q ...

  6. 被遗弃的depends2.2,替换解决方案——VS命令行

    vs的早期版本提供了depends工具,最新版本是2.2,已经不再更新了,网站是dependencywalker.com. 现在,我们可以使用vs开发人员命令行,dumpbin工具,导出二进制文件的信 ...

  7. Spark操作parquet文件

    package code.parquet import java.net.URI import org.apache.hadoop.conf.Configuration import org.apac ...

  8. MongoDB数据创建与使用

    MongoDB数据创建与使用 创建数据库 代码功能:读取本地文本文件,并保存到数据库中 import pymongo #连接mongo数据库 client = pymongo.MongoClient( ...

  9. Markdonw基本语法学习

    Markdonw基本语法 二级标题 三级标题 ----ctrl+r 粗体 ctrl+b 斜体 ctr+i #include<stdio.h> void main() { printf(&q ...

  10. 关于SqlServer数据表操作

    --修改表字段长度alter table Tbl_Count_User_Ref ALTER COLUMN CountName nvarchar(500);新增字段alter table 表名 add ...