mysql 遍历_MySQL 实现树的遍历详解及简单实现示例
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 实现树的遍历详解及简单实现示例相关推荐
- 二叉树的遍历及根据遍历反推树的方法详解
一.前导-关于树的定义 森林(forest):每个连通分量(连通块)都是树的图.按照定义,一棵树也是森林. 生成树(spanning tree):一个连通无向图的生成子图,同时要求是树.也即在图的边集 ...
- 组合索引mysql语句_Mysql之组合索引方法详解
对于任何DBMS,索引都是进行优化的最主要的因素.对于少量的数据,没有合适的索引影响不是很大,但是,当随着数据量的增加,性能会急剧下降. 如果对多列进行索引(组合索引),列的顺序非常重要,MySQL仅 ...
- mysql主从_MySQL主从原理及配置详解
MySQL主从配置及原理,供大家参考,具体内容如下 一.环境选择: 1.Centos 6.5 2.MySQL 5.7 二.什么是MySQL主从复制 MySQL主从复制是其最重要的功能之一.主从复制是指 ...
- mysql 堵塞_Mysql解决USE DB堵塞详解
遇到故障,我们往往想的是如何解决这个故障,而不是从故障的根本去思考出现这个故障的原因?这样的结果,只能使我们得到了鱼,失去了渔.今天,我们就来分享一个由USE DB堵塞故障引发的思考案例. 故障描述 ...
- mysql游标_MySQL游标概念与用法详解
本文实例讲述了MySQL游标概念与用法.分享给大家供大家参考,具体如下: 1.游标的概念(Cursor) 一条sql,对应N条资源,取出资源的接口,就是游标,沿着游标,可以一次取出1行.如果开发过安卓 ...
- mysql查询_MySQL基础,查询语句详解
使用 [GROUP BY ] [HAVING ] 进行分组查询(示例结果如图按顺序) 新增分组字段 ALTER TABLE study_1 ADD study_group int(11); 为原有的数 ...
- mysql 实例复制_MYSQL教程MySQL 复制详解及简单实例
<MysqL教程MysqL 复制详解及简单实例>要点: 本文介绍了MysqL教程MysqL 复制详解及简单实例,希望对您有用.如果有疑问,可以联系我们. MysqL 复制详解及简单实例 主 ...
- mysql 实例复制_MySQL 复制详解及简单实例
MySQL 复制详解及简单实例 主从复制技术在MySQL中被广泛使用,主要用于同步一台服务器上的数据至多台从服务器,可以用于实现负载均衡,高可用和故障切换,以及提供备份等等.MySQL支持多种不同的复 ...
- STM32固件库文件树及构成详解
(想要pfd格式文件的可以留下邮箱) STM32固件库文件树及构成详解(库版本:STM32F10x_StdPeriph_Lib_V3.5.0) 库减压后所有文件夹构成如下: /
最新文章
- 基于第四层交换技术的负载均衡
- 面试官:你能说说MyBatis拦截器原理吗?
- java 1.7 事件监听_17.7Listener监听器
- xargs的简单解析
- 利用JSP内置的Application对象实现的网站引用计数
- 运行在Docker里的SpringBoot应用,如何查看记录在文件系统的日志
- Nginx 禁止部分 User-Agrent 访问
- [Python2.x] 标准库 urllib2 的使用细节
- java actionscript_ActionScript(对比Java)学习笔记二
- 1636: Pascal山脉
- [paper reading] YOLO v1
- 使用Angular4手把手构建符合企业实际的项目管理系统----【npm】工具的使用
- java web 密码加密_JavaWeb日记——Shiro之密码加密
- lwip---(五)以太网数据接收
- 到底如何理解文本?一文读懂命名实体识别(实体消歧和实体统一)
- SIM卡中的ef文件介绍
- 只要五分钟,让你成功接入Twitter的第三方登录
- 项目管理软件用哪个好?推荐这6款项目管理工具
- 项目经理的软技能、硬技能
- 支持IEC 61850的设备,数据如何能有效的采集管理,如何实现数据可视化?
热门文章
- 基于C++的二叉树的入门讲解
- 剑指offer:面试题32 - II. 从上到下打印二叉树 II
- 在Ubuntu 14.04 64bit上生成ATS本地离线文档
- Blender中的主程序纹理学习课程 Master Procedural Texturing in Blender
- 二叉树:最近的公共祖先 Lowest Common Ancestor of a Binary Tree
- Linux进程描述符task_struct结构体简析
- C# 篇基础知识11——泛型和集合
- noip2010提高组3题题解 by rLq
- C++基础知识(二)
- javascript 利用 - 枚举思想 - 添加地名的一个小例子