MySQL 实现树的遍历

经常在一个表中有父子关系的两个字段,比如empno与manager,这种结构中需要用到树的遍历。在Oracle 中可以使用connect by简单解决问题,但MySQL 5.1中还不支持(据说已纳入to do中),要自己写过程或函数来实现。

一、建立测试表和数据:

DROP TABLE IF EXISTS `channel`;

CREATE TABLE `channel` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`cname` varchar(200) DEFAULT NULL,

`parent_id` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;

/*Data for the table `channel` */

insert into `channel`(`id`,`cname`,`parent_id`)

values (13,'首页',-1),

(14,'TV580',-1),

(15,'生活580',-1),

(16,'左上幻灯片',13),

(17,'帮忙',14),

(18,'栏目简介',17);

二、利用临时表和递归过程实现树的遍历(MySQL的UDF不能递归调用):

DELIMITER $$

USE `db1`$$

-- 从某节点向下遍历子节点

-- 递归生成临时表数据

DROP PROCEDURE IF EXISTS `createChildLst`$$

CREATE PROCEDURE `createChildLst`(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 tmpLst VALUES (NULL,rootId,nDepth);

OPEN cur1;

FETCH cur1 INTO b;

WHILE done=0 DO

CALL createChildLst(b,nDepth+1);

FETCH cur1 INTO b;

END WHILE;

CLOSE cur1;

END$$

-- 从某节点向上追溯根节点

-- 递归生成临时表数据

DROP PROCEDURE IF EXISTS `createParentLst`$$

CREATE PROCEDURE `createParentLst`(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 tmpLst VALUES (NULL,rootId,nDepth);

OPEN cur1;

FETCH cur1 INTO b;

WHILE done=0 DO

CALL createParentLst(b,nDepth+1);

FETCH cur1 INTO b;

END WHILE;

CLOSE cur1;

END$$

-- 实现类似Oracle SYS_CONNECT_BY_PATH的功能

-- 递归过程输出某节点id路径

DROP PROCEDURE IF EXISTS `createPathLst`$$

CREATE PROCEDURE `createPathLst`(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;

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 createPathLst(parentid,delimit,pathstr);

FETCH cur1 INTO parentid,pathstr;

END WHILE;

CLOSE cur1;

END$$

-- 递归过程输出某节点name路径

DROP PROCEDURE IF EXISTS `createPathnameLst`$$

CREATE PROCEDURE `createPathnameLst`(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;

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 createPathnameLst(parentid,delimit,pathstr);

FETCH cur1 INTO parentid,pathstr;

END WHILE;

CLOSE cur1;

END$$

-- 调用函数输出id路径

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 createPathLst(nid,delimit,@pathid);

RETURN @pathid;

END$$

-- 调用函数输出name路径

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 createPathnameLst(nid,delimit,@pathid);

RETURN @pathid;

END$$

-- 调用过程输出子节点

DROP PROCEDURE IF EXISTS `showChildLst`$$

CREATE PROCEDURE `showChildLst`(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 createChildLst(rootId,0);

SELECT channel.id,CONCAT(SPACE(tmpLst.depth*2),'--',channel.cname) NAME,channel.parent_id,tmpLst.depth,fn_tree_path(channel.id,'/') path,fn_tree_pathname(channel.id,'/') pathname

FROM tmpLst,channel WHERE tmpLst.id=channel.id ORDER BY tmpLst.sno;

END$$

-- 调用过程输出父节点

DROP PROCEDURE IF EXISTS `showParentLst`$$

CREATE PROCEDURE `showParentLst`(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 createParentLst(rootId,0);

SELECT channel.id,CONCAT(SPACE(tmpLst.depth*2),'--',channel.cname) NAME,channel.parent_id,tmpLst.depth,fn_tree_path(channel.id,'/') path,fn_tree_pathname(channel.id,'/') pathname

FROM tmpLst,channel WHERE tmpLst.id=channel.id ORDER BY tmpLst.sno;

END$$

DELIMITER ;

三、测试

CALL showChildLst(-1);

CALL showChildLst(13);

CALL showChildLst(14);

CALL showChildLst(17);

CALL showChildLst(18);

CALL showParentLst(-1);

CALL showParentLst(13);

CALL showParentLst(14);

CALL showParentLst(17);

CALL showParentLst(18);

四、遗留问题

1. 因为mysql对动态游标的支持不够,所以要想做成通用的过程或函数比较困难,可以利用两个临时表来转换(同时去掉了递归调用)是个相对通用的实现。

2. 目前来看无论哪种实现,效率都不太好,希望mysql自己能实现Oracle 的connect by 功能,应该会比较优化。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

mysql 遍历_MySQL 实现树的遍历详解及简单实现示例相关推荐

  1. 二叉树的遍历及根据遍历反推树的方法详解

    一.前导-关于树的定义 森林(forest):每个连通分量(连通块)都是树的图.按照定义,一棵树也是森林. 生成树(spanning tree):一个连通无向图的生成子图,同时要求是树.也即在图的边集 ...

  2. 组合索引mysql语句_Mysql之组合索引方法详解

    对于任何DBMS,索引都是进行优化的最主要的因素.对于少量的数据,没有合适的索引影响不是很大,但是,当随着数据量的增加,性能会急剧下降. 如果对多列进行索引(组合索引),列的顺序非常重要,MySQL仅 ...

  3. mysql主从_MySQL主从原理及配置详解

    MySQL主从配置及原理,供大家参考,具体内容如下 一.环境选择: 1.Centos 6.5 2.MySQL 5.7 二.什么是MySQL主从复制 MySQL主从复制是其最重要的功能之一.主从复制是指 ...

  4. mysql 堵塞_Mysql解决USE DB堵塞详解

    遇到故障,我们往往想的是如何解决这个故障,而不是从故障的根本去思考出现这个故障的原因?这样的结果,只能使我们得到了鱼,失去了渔.今天,我们就来分享一个由USE DB堵塞故障引发的思考案例. 故障描述 ...

  5. mysql游标_MySQL游标概念与用法详解

    本文实例讲述了MySQL游标概念与用法.分享给大家供大家参考,具体如下: 1.游标的概念(Cursor) 一条sql,对应N条资源,取出资源的接口,就是游标,沿着游标,可以一次取出1行.如果开发过安卓 ...

  6. mysql查询_MySQL基础,查询语句详解

    使用 [GROUP BY ] [HAVING ] 进行分组查询(示例结果如图按顺序) 新增分组字段 ALTER TABLE study_1 ADD study_group int(11); 为原有的数 ...

  7. mysql 实例复制_MYSQL教程MySQL 复制详解及简单实例

    <MysqL教程MysqL 复制详解及简单实例>要点: 本文介绍了MysqL教程MysqL 复制详解及简单实例,希望对您有用.如果有疑问,可以联系我们. MysqL 复制详解及简单实例 主 ...

  8. mysql 实例复制_MySQL 复制详解及简单实例

    MySQL 复制详解及简单实例 主从复制技术在MySQL中被广泛使用,主要用于同步一台服务器上的数据至多台从服务器,可以用于实现负载均衡,高可用和故障切换,以及提供备份等等.MySQL支持多种不同的复 ...

  9. STM32固件库文件树及构成详解

    (想要pfd格式文件的可以留下邮箱) STM32固件库文件树及构成详解(库版本:STM32F10x_StdPeriph_Lib_V3.5.0) 库减压后所有文件夹构成如下: /

最新文章

  1. 基于第四层交换技术的负载均衡
  2. 面试官:你能说说MyBatis拦截器原理吗?
  3. java 1.7 事件监听_17.7Listener监听器
  4. xargs的简单解析
  5. 利用JSP内置的Application对象实现的网站引用计数
  6. 运行在Docker里的SpringBoot应用,如何查看记录在文件系统的日志
  7. Nginx 禁止部分 User-Agrent 访问
  8. [Python2.x] 标准库 urllib2 的使用细节
  9. java actionscript_ActionScript(对比Java)学习笔记二
  10. 1636: Pascal山脉
  11. [paper reading] YOLO v1
  12. 使用Angular4手把手构建符合企业实际的项目管理系统----【npm】工具的使用
  13. java web 密码加密_JavaWeb日记——Shiro之密码加密
  14. lwip---(五)以太网数据接收
  15. 到底如何理解文本?一文读懂命名实体识别(实体消歧和实体统一)
  16. SIM卡中的ef文件介绍
  17. 只要五分钟,让你成功接入Twitter的第三方登录
  18. 项目管理软件用哪个好?推荐这6款项目管理工具
  19. 项目经理的软技能、硬技能
  20. 支持IEC 61850的设备,数据如何能有效的采集管理,如何实现数据可视化?

热门文章

  1. 基于C++的二叉树的入门讲解
  2. 剑指offer:面试题32 - II. 从上到下打印二叉树 II
  3. 在Ubuntu 14.04 64bit上生成ATS本地离线文档
  4. Blender中的主程序纹理学习课程 Master Procedural Texturing in Blender
  5. 二叉树:最近的公共祖先 Lowest Common Ancestor of a Binary Tree
  6. Linux进程描述符task_struct结构体简析
  7. C# 篇基础知识11——泛型和集合
  8. noip2010提高组3题题解 by rLq
  9. C++基础知识(二)
  10. javascript 利用 - 枚举思想 - 添加地名的一个小例子