经常在一个表中有父子关系的两个字段,比如empno与manager,这种结构中需要用到树的遍历。在Oracle中可以使用connect by简单解决问题,参见http://blog.csdn.net/wzy0623/archive/2007/06/18/1656345.aspx,但MySQL5.1中还不支持(据说已纳入to do中),要自己写过程或函数来实现。
一、建立测试表和数据:
- DROPTABLEIFEXISTS`channel`;
- CREATETABLE`channel`(
- `id`int(11)NOTNULLAUTO_INCREMENT,
- `cname`varchar(200)DEFAULTNULL,
- `parent_id`int(11)DEFAULTNULL,
- PRIMARYKEY(`id`)
- )ENGINE=MyISAMAUTO_INCREMENT=19DEFAULTCHARSET=utf8;
- insertinto`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`$$
- --从某节点向下遍历子节点
- --递归生成临时表数据
- DROPPROCEDUREIFEXISTS`createChildLst`$$
- CREATEPROCEDURE`createChildLst`(INrootIdINT,INnDepthINT)
- BEGIN
- DECLAREdoneINTDEFAULT0;
- DECLAREbINT;
- DECLAREcur1CURSORFORSELECTidFROMchannelWHEREparent_id=rootId;
- DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
- SETmax_sp_recursion_depth=12;
- INSERTINTOtmpLstVALUES(NULL,rootId,nDepth);
- OPENcur1;
- FETCHcur1INTOb;
- WHILEdone=0DO
- CALLcreateChildLst(b,nDepth+1);
- FETCHcur1INTOb;
- ENDWHILE;
- CLOSEcur1;
- END$$
- --从某节点向上追溯根节点
- --递归生成临时表数据
- DROPPROCEDUREIFEXISTS`createParentLst`$$
- CREATEPROCEDURE`createParentLst`(INrootIdINT,INnDepthINT)
- BEGIN
- DECLAREdoneINTDEFAULT0;
- DECLAREbINT;
- DECLAREcur1CURSORFORSELECTparent_idFROMchannelWHEREid=rootId;
- DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
- SETmax_sp_recursion_depth=12;
- INSERTINTOtmpLstVALUES(NULL,rootId,nDepth);
- OPENcur1;
- FETCHcur1INTOb;
- WHILEdone=0DO
- CALLcreateParentLst(b,nDepth+1);
- FETCHcur1INTOb;
- ENDWHILE;
- CLOSEcur1;
- END$$
- --实现类似OracleSYS_CONNECT_BY_PATH的功能
- --递归过程输出某节点id路径
- DROPPROCEDUREIFEXISTS`createPathLst`$$
- CREATEPROCEDURE`createPathLst`(INnidINT,INdelimitVARCHAR(10),INOUTpathstrVARCHAR(1000))
- BEGIN
- DECLAREdoneINTDEFAULT0;
- DECLAREparentidINTDEFAULT0;
- DECLAREcur1CURSORFOR
- SELECTt.parent_id,CONCAT(CAST(t.parent_idASCHAR),delimit,pathstr)
- FROMchannelAStWHEREt.id=nid;
- DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
- SETmax_sp_recursion_depth=12;
- OPENcur1;
- FETCHcur1INTOparentid,pathstr;
- WHILEdone=0DO
- CALLcreatePathLst(parentid,delimit,pathstr);
- FETCHcur1INTOparentid,pathstr;
- ENDWHILE;
- CLOSEcur1;
- END$$
- --递归过程输出某节点name路径
- DROPPROCEDUREIFEXISTS`createPathnameLst`$$
- CREATEPROCEDURE`createPathnameLst`(INnidINT,INdelimitVARCHAR(10),INOUTpathstrVARCHAR(1000))
- BEGIN
- DECLAREdoneINTDEFAULT0;
- DECLAREparentidINTDEFAULT0;
- DECLAREcur1CURSORFOR
- SELECTt.parent_id,CONCAT(t.cname,delimit,pathstr)
- FROMchannelAStWHEREt.id=nid;
- DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
- SETmax_sp_recursion_depth=12;
- OPENcur1;
- FETCHcur1INTOparentid,pathstr;
- WHILEdone=0DO
- CALLcreatePathnameLst(parentid,delimit,pathstr);
- FETCHcur1INTOparentid,pathstr;
- ENDWHILE;
- CLOSEcur1;
- END$$
- --调用函数输出id路径
- DROPFUNCTIONIFEXISTS`fn_tree_path`$$
- CREATEFUNCTION`fn_tree_path`(nidINT,delimitVARCHAR(10))RETURNSVARCHAR(2000)CHARSETutf8
- BEGIN
- DECLAREpathidVARCHAR(1000);
- SET@pathid=CAST(nidASCHAR);
- CALLcreatePathLst(nid,delimit,@pathid);
- RETURN@pathid;
- END$$
- --调用函数输出name路径
- DROPFUNCTIONIFEXISTS`fn_tree_pathname`$$
- CREATEFUNCTION`fn_tree_pathname`(nidINT,delimitVARCHAR(10))RETURNSVARCHAR(2000)CHARSETutf8
- BEGIN
- DECLAREpathidVARCHAR(1000);
- SET@pathid='';
- CALLcreatePathnameLst(nid,delimit,@pathid);
- RETURN@pathid;
- END$$
- --调用过程输出子节点
- DROPPROCEDUREIFEXISTS`showChildLst`$$
- CREATEPROCEDURE`showChildLst`(INrootIdINT)
- BEGIN
- DROPTEMPORARYTABLEIFEXISTStmpLst;
- CREATETEMPORARYTABLEIFNOTEXISTStmpLst
- (snoINTPRIMARYKEYAUTO_INCREMENT,idINT,depthINT);
- CALLcreateChildLst(rootId,0);
- SELECTchannel.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
- FROMtmpLst,channelWHEREtmpLst.id=channel.idORDERBYtmpLst.sno;
- END$$
- --调用过程输出父节点
- DROPPROCEDUREIFEXISTS`showParentLst`$$
- CREATEPROCEDURE`showParentLst`(INrootIdINT)
- BEGIN
- DROPTEMPORARYTABLEIFEXISTStmpLst;
- CREATETEMPORARYTABLEIFNOTEXISTStmpLst
- (snoINTPRIMARYKEYAUTO_INCREMENT,idINT,depthINT);
- CALLcreateParentLst(rootId,0);
- SELECTchannel.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
- FROMtmpLst,channelWHEREtmpLst.id=channel.idORDERBYtmpLst.sno;
- END$$
- DELIMITER;
三、测试
- CALLshowChildLst(-1);
- CALLshowChildLst(13);
- CALLshowChildLst(14);
- CALLshowChildLst(17);
- CALLshowChildLst(18);
- CALLshowParentLst(-1);
- CALLshowParentLst(13);
- CALLshowParentLst(14);
- CALLshowParentLst(17);
- CALLshowParentLst(18);
四、遗留问题
1. 因为mysql对动态游标的支持不够,所以要想做成通用的过程或函数比较困难,可以利用两个临时表来转换(同时去掉了递归调用)参考http://jan.kneschke.de/projects/mysql/sp/sp_tree.sql,是个相对通用的实现。
2. 目前来看无论哪种实现,效率都不太好,希望mysql自己能实现oracle 的connect by 功能,应该会比较优化。
参考:MySQL中进行树状所有子节点的查询
分享到:
相关推荐
利用MySQL存储过程实现树的初始化、插入、深度遍历、按层遍历、删除操作。可以作为学习存储过程的笑demo
本文将详细介绍如何在MySQL中实现树的遍历,并提供一个简单的实现示例。 首先,我们需要创建一个具有层级关系的测试表。例如,我们可以创建一个名为`channel`的表,其中包含`id`作为主键,`cname`存储节点名称,...
总结来说,树的前序遍历是理解树数据结构的基础,无论在JAVA还是SQL中,都有相应的实现策略。掌握这一概念对于解决各种计算机科学问题,尤其是数据结构和算法设计,都至关重要。在实际应用中,应根据具体需求选择...
本文将深入探讨如何利用Java语言和MySQL数据库来实现这一功能,解析给定代码片段,并提供一种高效遍历树形结构的方法。 ### 一、理解树形结构 树形结构是一种非线性的数据结构,它由节点和边组成,其中每个节点...
在"TreeTraversal-master"这个压缩包中,很可能包含了一个示例项目,演示了如何在MySQL中实现嵌套集模型和树遍历。通过阅读源代码和运行示例,你可以更深入地理解这些概念,并将其应用到自己的项目中。记得根据实际...
递归存储过程是一种特殊的存储过程,可以递归调用自身,以实现树形结构的查询。递归存储过程可以根据需要设置递归深度,以控制查询的深度。 在上面的例子中,我们定义了两个存储过程:findLChild 和 iterative。...
"Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】" Java二叉搜索树是一种常用的数据结构,遍历操作是其核心内容。Java二叉搜索树遍历操作可以分为五种:前序遍历、中序遍历、后序遍历、层次...
前序遍历作为一种有效的树遍历方法,被广泛应用于解决此类问题,因为它能提供更好的性能和灵活性。本文将深入探讨前序遍历树模型,以及如何利用它来优化无限分类的处理。 首先,我们来看一下无限分类的需求。在许多...
MySQL 实现无限级分类是一种常见的数据库设计挑战,特别是在需要构建层级结构的数据模型时,例如网站导航菜单、组织架构或商品分类。以下将详细介绍三种常见的无限级分类实现方法,并分析其优缺点。 ### 1. 递归...
我这里已经把分类的移动和排序都重新处理了,实现了MPTT分类的排序和移动 为了保证分类左右节点的连续性,这个存储过程有检测节点连续性和完整性的处理。 理论上不会因为在添加、修改、删除、移动或者排序的操作中...
给定的代码片段展示了如何在JSP中实现树形数据结构的遍历。首先,我们看到一个私有方法`tree`,它接受三个参数:数据库连接`conn`、当前节点的ID`id`以及当前层级`level`。这个方法的主要目的是构建并显示树形结构,...
利用存储过程实现树的初始化、插入、按层遍历、深度遍历、删除操作。可以作为学习存储过程的例子。
本项目利用JavaScript(JS)、Java服务器页面(JSP)以及MySQL数据库来实现这样一个无限树形结构。 **1. JavaScript** JavaScript 是一种客户端脚本语言,主要用于网页交互和动态效果。在这个项目中,JS 主要负责...
本文详细介绍了如何使用 PHP 和 MySQL 实现对数据库中树形结构的遍历。通过递归的方式实现了树形结构的深度优先遍历,适用于多种场景下的数据处理需求。此外,还涉及到了环境配置、类文件加载、配置文件读取等实际...
Zebra_MPTT是一个PHP类,提供了修改后的预排序树遍历算法的实现,使您可以轻松地在PHP应用程序中使用MPTT。 它提供了在树中任何位置添加节点,删除节点,在树周围移动和复制节点的方法,以及检索有关节点的各种信息...
这里我们将深入探讨如何在MySQL中使用存储过程来实现这一功能。 首先,为了理解这个过程,我们需要一个具有层级关系的数据表。在给出的`treenodes.sql`脚本文件中,很可能定义了一个类似这样的表: ```sql CREATE ...
这涉及到数据库连接的知识,通常我们需要使用像`mysql-connector-python`这样的库来实现Python环境下的连接。连接参数包括主机名(IP)、用户名、密码和数据库名称,通过这些参数创建数据库连接,并执行SQL查询来...