`
king_tt
  • 浏览: 2234175 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

MySQL实现树的遍历

 
阅读更多

经常在一个表中有父子关系的两个字段,比如empno与manager,这种结构中需要用到树的遍历。在Oracle中可以使用connect by简单解决问题,参见http://blog.csdn.net/wzy0623/archive/2007/06/18/1656345.aspx,但MySQL5.1中还不支持(据说已纳入to do中),要自己写过程或函数来实现。


一、建立测试表和数据:

[c-sharp]view plaincopy
  1. DROPTABLEIFEXISTS`channel`;
  2. CREATETABLE`channel`(
  3. `id`int(11)NOTNULLAUTO_INCREMENT,
  4. `cname`varchar(200)DEFAULTNULL,
  5. `parent_id`int(11)DEFAULTNULL,
  6. PRIMARYKEY(`id`)
  7. )ENGINE=MyISAMAUTO_INCREMENT=19DEFAULTCHARSET=utf8;
  8. /*Dataforthetable`channel`*/
  9. insertinto`channel`(`id`,`cname`,`parent_id`)
  10. values(13,'首页',-1),
  11. (14,'TV580',-1),
  12. (15,'生活580',-1),
  13. (16,'左上幻灯片',13),
  14. (17,'帮忙',14),
  15. (18,'栏目简介',17);

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

[c-sharp]view plaincopy
  1. DELIMITER$$
  2. USE`db1`$$
  3. --从某节点向下遍历子节点
  4. --递归生成临时表数据
  5. DROPPROCEDUREIFEXISTS`createChildLst`$$
  6. CREATEPROCEDURE`createChildLst`(INrootIdINT,INnDepthINT)
  7. BEGIN
  8. DECLAREdoneINTDEFAULT0;
  9. DECLAREbINT;
  10. DECLAREcur1CURSORFORSELECTidFROMchannelWHEREparent_id=rootId;
  11. DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
  12. SETmax_sp_recursion_depth=12;
  13. INSERTINTOtmpLstVALUES(NULL,rootId,nDepth);
  14. OPENcur1;
  15. FETCHcur1INTOb;
  16. WHILEdone=0DO
  17. CALLcreateChildLst(b,nDepth+1);
  18. FETCHcur1INTOb;
  19. ENDWHILE;
  20. CLOSEcur1;
  21. END$$
  22. --从某节点向上追溯根节点
  23. --递归生成临时表数据
  24. DROPPROCEDUREIFEXISTS`createParentLst`$$
  25. CREATEPROCEDURE`createParentLst`(INrootIdINT,INnDepthINT)
  26. BEGIN
  27. DECLAREdoneINTDEFAULT0;
  28. DECLAREbINT;
  29. DECLAREcur1CURSORFORSELECTparent_idFROMchannelWHEREid=rootId;
  30. DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
  31. SETmax_sp_recursion_depth=12;
  32. INSERTINTOtmpLstVALUES(NULL,rootId,nDepth);
  33. OPENcur1;
  34. FETCHcur1INTOb;
  35. WHILEdone=0DO
  36. CALLcreateParentLst(b,nDepth+1);
  37. FETCHcur1INTOb;
  38. ENDWHILE;
  39. CLOSEcur1;
  40. END$$
  41. --实现类似OracleSYS_CONNECT_BY_PATH的功能
  42. --递归过程输出某节点id路径
  43. DROPPROCEDUREIFEXISTS`createPathLst`$$
  44. CREATEPROCEDURE`createPathLst`(INnidINT,INdelimitVARCHAR(10),INOUTpathstrVARCHAR(1000))
  45. BEGIN
  46. DECLAREdoneINTDEFAULT0;
  47. DECLAREparentidINTDEFAULT0;
  48. DECLAREcur1CURSORFOR
  49. SELECTt.parent_id,CONCAT(CAST(t.parent_idASCHAR),delimit,pathstr)
  50. FROMchannelAStWHEREt.id=nid;
  51. DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
  52. SETmax_sp_recursion_depth=12;
  53. OPENcur1;
  54. FETCHcur1INTOparentid,pathstr;
  55. WHILEdone=0DO
  56. CALLcreatePathLst(parentid,delimit,pathstr);
  57. FETCHcur1INTOparentid,pathstr;
  58. ENDWHILE;
  59. CLOSEcur1;
  60. END$$
  61. --递归过程输出某节点name路径
  62. DROPPROCEDUREIFEXISTS`createPathnameLst`$$
  63. CREATEPROCEDURE`createPathnameLst`(INnidINT,INdelimitVARCHAR(10),INOUTpathstrVARCHAR(1000))
  64. BEGIN
  65. DECLAREdoneINTDEFAULT0;
  66. DECLAREparentidINTDEFAULT0;
  67. DECLAREcur1CURSORFOR
  68. SELECTt.parent_id,CONCAT(t.cname,delimit,pathstr)
  69. FROMchannelAStWHEREt.id=nid;
  70. DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=1;
  71. SETmax_sp_recursion_depth=12;
  72. OPENcur1;
  73. FETCHcur1INTOparentid,pathstr;
  74. WHILEdone=0DO
  75. CALLcreatePathnameLst(parentid,delimit,pathstr);
  76. FETCHcur1INTOparentid,pathstr;
  77. ENDWHILE;
  78. CLOSEcur1;
  79. END$$
  80. --调用函数输出id路径
  81. DROPFUNCTIONIFEXISTS`fn_tree_path`$$
  82. CREATEFUNCTION`fn_tree_path`(nidINT,delimitVARCHAR(10))RETURNSVARCHAR(2000)CHARSETutf8
  83. BEGIN
  84. DECLAREpathidVARCHAR(1000);
  85. SET@pathid=CAST(nidASCHAR);
  86. CALLcreatePathLst(nid,delimit,@pathid);
  87. RETURN@pathid;
  88. END$$
  89. --调用函数输出name路径
  90. DROPFUNCTIONIFEXISTS`fn_tree_pathname`$$
  91. CREATEFUNCTION`fn_tree_pathname`(nidINT,delimitVARCHAR(10))RETURNSVARCHAR(2000)CHARSETutf8
  92. BEGIN
  93. DECLAREpathidVARCHAR(1000);
  94. SET@pathid='';
  95. CALLcreatePathnameLst(nid,delimit,@pathid);
  96. RETURN@pathid;
  97. END$$
  98. --调用过程输出子节点
  99. DROPPROCEDUREIFEXISTS`showChildLst`$$
  100. CREATEPROCEDURE`showChildLst`(INrootIdINT)
  101. BEGIN
  102. DROPTEMPORARYTABLEIFEXISTStmpLst;
  103. CREATETEMPORARYTABLEIFNOTEXISTStmpLst
  104. (snoINTPRIMARYKEYAUTO_INCREMENT,idINT,depthINT);
  105. CALLcreateChildLst(rootId,0);
  106. 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
  107. FROMtmpLst,channelWHEREtmpLst.id=channel.idORDERBYtmpLst.sno;
  108. END$$
  109. --调用过程输出父节点
  110. DROPPROCEDUREIFEXISTS`showParentLst`$$
  111. CREATEPROCEDURE`showParentLst`(INrootIdINT)
  112. BEGIN
  113. DROPTEMPORARYTABLEIFEXISTStmpLst;
  114. CREATETEMPORARYTABLEIFNOTEXISTStmpLst
  115. (snoINTPRIMARYKEYAUTO_INCREMENT,idINT,depthINT);
  116. CALLcreateParentLst(rootId,0);
  117. 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
  118. FROMtmpLst,channelWHEREtmpLst.id=channel.idORDERBYtmpLst.sno;
  119. END$$
  120. DELIMITER;


三、测试


[c-sharp]view plaincopy
  1. CALLshowChildLst(-1);
  2. CALLshowChildLst(13);
  3. CALLshowChildLst(14);
  4. CALLshowChildLst(17);
  5. CALLshowChildLst(18);
  6. CALLshowParentLst(-1);
  7. CALLshowParentLst(13);
  8. CALLshowParentLst(14);
  9. CALLshowParentLst(17);
  10. CALLshowParentLst(18);

四、遗留问题
1. 因为mysql对动态游标的支持不够,所以要想做成通用的过程或函数比较困难,可以利用两个临时表来转换(同时去掉了递归调用)参考http://jan.kneschke.de/projects/mysql/sp/sp_tree.sql,是个相对通用的实现。
2. 目前来看无论哪种实现,效率都不太好,希望mysql自己能实现oracle 的connect by 功能,应该会比较优化。

参考:MySQL中进行树状所有子节点的查询

分享到:
评论

相关推荐

    MySQL存储过程实现树的遍历

    利用MySQL存储过程实现树的初始化、插入、深度遍历、按层遍历、删除操作。可以作为学习存储过程的笑demo

    MySQL 实现树的遍历详解及简单实现示例

    本文将详细介绍如何在MySQL中实现树的遍历,并提供一个简单的实现示例。 首先,我们需要创建一个具有层级关系的测试表。例如,我们可以创建一个名为`channel`的表,其中包含`id`作为主键,`cname`存储节点名称,...

    树的前序遍历

    总结来说,树的前序遍历是理解树数据结构的基础,无论在JAVA还是SQL中,都有相应的实现策略。掌握这一概念对于解决各种计算机科学问题,尤其是数据结构和算法设计,都至关重要。在实际应用中,应根据具体需求选择...

    在java中 遍历mysql中的树形结构

    本文将深入探讨如何利用Java语言和MySQL数据库来实现这一功能,解析给定代码片段,并提供一种高效遍历树形结构的方法。 ### 一、理解树形结构 树形结构是一种非线性的数据结构,它由节点和边组成,其中每个节点...

    TreeTraversal:MySQL树遍历的实际例子

    在"TreeTraversal-master"这个压缩包中,很可能包含了一个示例项目,演示了如何在MySQL中实现嵌套集模型和树遍历。通过阅读源代码和运行示例,你可以更深入地理解这些概念,并将其应用到自己的项目中。记得根据实际...

    mysql 树形结构查询

    递归存储过程是一种特殊的存储过程,可以递归调用自身,以实现树形结构的查询。递归存储过程可以根据需要设置递归深度,以控制查询的深度。 在上面的例子中,我们定义了两个存储过程:findLChild 和 iterative。...

    Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】

    "Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】" Java二叉搜索树是一种常用的数据结构,遍历操作是其核心内容。Java二叉搜索树遍历操作可以分为五种:前序遍历、中序遍历、后序遍历、层次...

    前序遍历树—–关于无限分类的问题

    前序遍历作为一种有效的树遍历方法,被广泛应用于解决此类问题,因为它能提供更好的性能和灵活性。本文将深入探讨前序遍历树模型,以及如何利用它来优化无限分类的处理。 首先,我们来看一下无限分类的需求。在许多...

    mysql 无限级分类实现思路

    MySQL 实现无限级分类是一种常见的数据库设计挑战,特别是在需要构建层级结构的数据模型时,例如网站导航菜单、组织架构或商品分类。以下将详细介绍三种常见的无限级分类实现方法,并分析其优缺点。 ### 1. 递归...

    预排序遍历树算法的无限级分类-存储过程实现

    我这里已经把分类的移动和排序都重新处理了,实现了MPTT分类的排序和移动 为了保证分类左右节点的连续性,这个存储过程有检测节点连续性和完整性的处理。 理论上不会因为在添加、修改、删除、移动或者排序的操作中...

    JSP_遍历树(递归)

    给定的代码片段展示了如何在JSP中实现树形数据结构的遍历。首先,我们看到一个私有方法`tree`,它接受三个参数:数据库连接`conn`、当前节点的ID`id`以及当前层级`level`。这个方法的主要目的是构建并显示树形结构,...

    MySQL存储过程实现树的操作

    利用存储过程实现树的初始化、插入、按层遍历、深度遍历、删除操作。可以作为学习存储过程的例子。

    JS + JSP + MYSQL 无限树

    本项目利用JavaScript(JS)、Java服务器页面(JSP)以及MySQL数据库来实现这样一个无限树形结构。 **1. JavaScript** JavaScript 是一种客户端脚本语言,主要用于网页交互和动态效果。在这个项目中,JS 主要负责...

    PHP 数据库树的遍历方法

    本文详细介绍了如何使用 PHP 和 MySQL 实现对数据库中树形结构的遍历。通过递归的方式实现了树形结构的深度优先遍历,适用于多种场景下的数据处理需求。此外,还涉及到了环境配置、类文件加载、配置文件读取等实际...

    Zebra_MPTT:改进的预排序树遍历算法PHP实现-开源

    Zebra_MPTT是一个PHP类,提供了修改后的预排序树遍历算法的实现,使您可以轻松地在PHP应用程序中使用MPTT。 它提供了在树中任何位置添加节点,删除节点,在树周围移动和复制节点的方法,以及检索有关节点的各种信息...

    mysql递归调用获取树节点(子树)

    这里我们将深入探讨如何在MySQL中使用存储过程来实现这一功能。 首先,为了理解这个过程,我们需要一个具有层级关系的数据表。在给出的`treenodes.sql`脚本文件中,很可能定义了一个类似这样的表: ```sql CREATE ...

    mysql数据表导出生成xml文件和树形结构

    这涉及到数据库连接的知识,通常我们需要使用像`mysql-connector-python`这样的库来实现Python环境下的连接。连接参数包括主机名(IP)、用户名、密码和数据库名称,通过这些参数创建数据库连接,并执行SQL查询来...

Global site tag (gtag.js) - Google Analytics