在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点。但很遗憾,在MySQL的目前版本中还没有对应的功能。

在MySQL中如果是有限的层次,比如我们事先如果可以确定这个树的最大深度是4, 那么所有节点为根的树的深度均不会超过4,则我们可以直接通过left join 来实现。

但很多时候我们无法控制树的深度。这时就需要在MySQL中用存储过程来实现或在你的程序中来实现这个递归。本文讨论一下几种实现的方法。

样例数据:

mysql> create table treeNodes
    -> (
    ->  id int primary key,
    ->  nodename varchar(20),
    ->  pid int
    -> );
Query OK, 0 rows affected (0.09 sec) 
mysql> select * from treenodes;
+----+----------+------+
| id | nodename | pid  |
+----+----------+------+
|  1 | A        |    0 |
|  2 | B        |    1 |
|  3 | C        |    1 |
|  4 | D        |    2 |
|  5 | E        |    2 |
|  6 | F        |    3 |
|  7 | G        |    6 |
|  8 | H        |    0 |
|  9 | I        |    8 |
| 10 | J        |    8 |
| 11 | K        |    8 |
| 12 | L        |    9 |
| 13 | M        |    9 |
| 14 | N        |   12 |
| 15 | O        |   12 |
| 16 | P        |   15 |
| 17 | Q        |   15 |
+----+----------+------+
17 rows in set (0.00 sec)

树形图如下

1:A
  +-- 2:B
  |    +-- 4:D
  |    +-- 5:E
  +-- 3:C
       +-- 6:F
            +-- 7:G
8:H
  +-- 9:I
  |    +-- 12:L
  |    |    +--14:N
  |    |    +--15:O
  |    |        +--16:P
  |    |        +--17:Q
  |    +-- 13:M
  +-- 10:J
  +-- 11:K

方法一:利用函数来得到所有子节点号

创建一个function getChildLst, 得到一个由所有子节点号组成的字符串.

mysql> delimiter //
mysql>
mysql> CREATE FUNCTION `getChildLst`(rootId INT)
    -> RETURNS varchar(1000)
    -> BEGIN
    ->   DECLARE sTemp VARCHAR(1000);
    ->   DECLARE sTempChd VARCHAR(1000);
    ->
    ->   SET sTemp = '$';
    ->   SET sTempChd =cast(rootId as CHAR);
    ->
    ->   WHILE sTempChd is not null DO
    ->     SET sTemp = concat(sTemp,',',sTempChd);
    ->     SELECT group_concat(id) INTO sTempChd FROM treeNodes where FIND_IN_SET(pid,sTempChd)>0;
    ->   END WHILE;
    ->   RETURN sTemp;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> delimiter ;

使用我们直接利用find_in_set函数配合这个getChildlst来查找

mysql> select getChildLst(1);
+-----------------+
| getChildLst(1)  |
+-----------------+
| $,1,2,3,4,5,6,7 |
+-----------------+
1 row in set (0.00 sec) 
mysql> select * from treeNodes
    -> where FIND_IN_SET(id, getChildLst(1));
+----+----------+------+
| id | nodename | pid  |
+----+----------+------+
|  1 | A        |    0 |
|  2 | B        |    1 |
|  3 | C        |    1 |
|  4 | D        |    2 |
|  5 | E        |    2 |
|  6 | F        |    3 |
|  7 | G        |    6 |
+----+----------+------+
7 rows in set (0.01 sec)
mysql> select * from treeNodes
    -> where FIND_IN_SET(id, getChildLst(3));
+----+----------+------+
| id | nodename | pid  |
+----+----------+------+
|  3 | C        |    1 |
|  6 | F        |    3 |
|  7 | G        |    6 |
+----+----------+------+
3 rows in set (0.01 sec)

优点: 简单,方便,没有递归调用层次深度的限制 (max_sp_recursion_depth,最大255) ;

缺点:长度受限,虽然可以扩大 RETURNS varchar(1000),但总是有最大限制的。

MySQL目前版本( 5.1.33-community)中还不支持function 的递归调用。

利用函数来得到所有子节点号& 利用函数来取得最高级的节点号的更多相关文章

  1. 节点地址的函数list_entry()原理详解

    本节中,我们继续讲解,在linux2.4内核下,如果通过一些列函数从路径名找到目标节点. 3.3.1)接下来查看chached_lookup()的代码(namei.c) [path_walk()> ...

  2. 算法初级面试题05——哈希函数/表、生成多个哈希函数、哈希扩容、利用哈希分流找出大文件的重复内容、设计RandomPool结构、布隆过滤器、一致性哈希、并查集、岛问题

    今天主要讨论:哈希函数.哈希表.布隆过滤器.一致性哈希.并查集的介绍和应用. 题目一 认识哈希函数和哈希表 1.输入无限大 2.输出有限的S集合 3.输入什么就输出什么 4.会发生哈希碰撞 5.会均匀 ...

  3. python中获取当前位置所在的行号和函数名(转)

    http://www.vimer.cn/2010/12/%E5%9C%A8python%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E4%BD%8D%E7 ...

  4. python中获取当前位置所在的行号和函数名(转)

    http://www.vimer.cn/2010/12/%E5%9C%A8python%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E4%BD%8D%E7 ...

  5. python利用or在列表解析中调用多个函数.py

    python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...

  6. php信用卡卡号验证函数

    介绍一个php信用卡卡号验证函数,可以验证一个卡号是否是信用卡. function validateCard ($cardnumber){ $cardnumber = preg_replace (&q ...

  7. 利用phpqrcode二维码生成类库和imagecopymerge函数制拼接图片的经验

    前期准备 引入phpqrcode类库(下载地址:https://sourceforge.net/projects/phpqrcode/) PHP开启GD扩展库支持 1.利用phpqrcode生成二维码 ...

  8. C/C++ 打印文件名、行号、函数名的方法

    转自:http://zhidao.baidu.com/link?url=JLCaxBAXLJVcx_8jsyJVF92E_bZjo4ONJ5Ab-HGlNBc1dfzcAyFAIygwP1qr18aa ...

  9. Redis笔记 -- 链表和链表节点的API函数(三)

    链表和链表节点API 函数 作用 时间复杂度 listSetDupMethod 将给定的函数设置为链表的节点值复制函数 复制函数可以通过链表的dup属性直接获得,O(1) listGetDupMeth ...

随机推荐

  1. WPF ICommandSource Implementations Leak Memory!

    Actually the title of this article should be entitled "How to use WeakEventManager with IComman ...

  2. 8个日志级别(OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL)

    log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),优先级从高到低依次为:OFF.FATAL.ERROR.WARN.INFO.DEBUG.TRACE. ALL. ALL 最低等 ...

  3. 浅谈C++中对象的复制与对象之间的相互赋值

    C++对象的复制 有时需要用到多个完全相同的对象,例如,同一型号的每一个产品从外表到内部属性都是一样的,如果要对每一个产品分别进行处理,就需要建立多个同样的对象,并要进行相同的初始化,用以前的办法定义 ...

  4. MyGUI 解析

    MyGUI源码还是比较简单的,我们在这里只是简单分析相应控件如何生成,如何渲染. 我们分成三个部分来说明,分别是资源类型,控件生成,控件渲染. 资源类型: ResourceSkin:用于记录各个控件状 ...

  5. (笔记)Linux Socket通信:bind: Address already in use

    在网络通信时使用Bind绑定IP地址跟端口号时,有时Ctrl+C强制结束进程之后,再次运行程序Bind错误,原因如下: 虽然用Ctrl+C强制结束了进程,但错误依然存在,用netstat -an |g ...

  6. android 8 wifi wifi 扫描过程

    查看一下android wifi扫描的过程. packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java public ...

  7. e840. 监听JTabbedPane中选中卡片的改变

    A tabbed pane fires a change event whenever the selected tab is changed either by the user or progra ...

  8. e739. 创建一个标签组件

    // The text is left-justified and vertically centered JLabel label = new JLabel("Text Label&quo ...

  9. XAudio2学习之调节音调

    频率比有两个地方能够设置.一个是在创建IXAudio2SourceVoice对象的时候.一个是调用IXAudio2SourceVoice::SetFrequencyRatio来调节. 在创建IXAud ...

  10. Python内部机制。

    type ,object ,__class__ ,__bases__ ,__metaclass__ , -------------------------不明白的地方----------------- ...