mysql笔记(一):递归分类层次查询

1. 问题描述:

工作中遇到一个需求,对于一个典型的递归层次分类结构表(组织机构表),要求根据某个节点值找到节点及其所有父级节点。

(1)示例表结构:

mysql> desc class;
+-------------+-------------+------+-----+---------+-------+
| Field       | Type        | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| org_code    | varchar(20) | NO   |     | NULL    |       |
| parent_code | varchar(20) | YES  |     | NULL    |       |
+-------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

(2)示例表数据:

mysql> select * from class;
+--------------+-------------+
| org_code     | parent_code |
+--------------+-------------+
| 0001         | NULL        |
| 00010001     | 0001        |
| 00010002     | 0001        |
| 000100010001 | 00010001    |
| 00010003     | 0001        |
| 000100010002 | 0001        |
+--------------+-------------+
6 rows in set (0.00 sec)

2. 问题分析

    不想专门加一个函数来做这件事,就想着用sql语句自身的能力来解决类似递归的查询。记得在《mysql技术内幕:sql编程》中解决间断区间问题的一个解决思路:通过自定义变量来记录上一行的值,那我是不是可以自定义变量记录上一个匹配行中父节点的值,进而找到所有匹配行呢?

    貌似可以,但是这两个问题还是有本质不同的,关键区别是前者是一个有序数列,而我这里的数据是无序的字符串编码,所以我需要把它排个序,目的是让所有匹配行的父节点相关的行在其后面出现,这样我每次记录的新的父节点值就都能在接下来的行中找到啦,幸亏我这里的编码是有层次嵌套规则的,所以按照字符串降序就可以了。

(1)排序

mysql> select * from class order by org_code desc;
+--------------+-------------+
| org_code     | parent_code |
+--------------+-------------+
| 00010003     | 0001        |
| 00010002     | 0001        |
| 000100010002 | 0001        |
| 000100010001 | 00010001    |
| 00010001     | 0001        |
| 0001         | NULL        |
+--------------+-------------+
6 rows in set (0.03 sec)

(2)逐行过滤记录,更新匹配值为匹配行的父节点

mysql> select (case when org_code=@r then org_code else null end) as code,
    ->        (case when org_code=@r then @r:=parent_code else null end) as parent
    ->     from (select org_code,parent_code from class order by org_code DESC) as c,(select @r:='000100010001') as t;
+--------------+----------+
| code         | parent   |
+--------------+----------+
| NULL         | NULL     |
| NULL         | NULL     |
| NULL         | NULL     |
| 000100010001 | 00010001 |
| 00010001     | 0001     |
| 0001         | NULL     |
+--------------+----------+
6 rows in set (0.03 sec)

(3)筛选匹配行

mysql> select code,parent from 
    ->     (select (case when org_code=@r then org_code else null end) as code,
    ->             (case when org_code=@r then @r:=parent_code else null end) as parent
    ->     from (select org_code,parent_code from class order by org_code DESC) as c,(select @r:='000100010001') as t) as tmp 
    -> where code is not null;
+--------------+----------+
| code         | parent   |
+--------------+----------+
| 000100010001 | 00010001 |
| 00010001     | 0001     |
| 0001         | NULL     |
+--------------+----------+
3 rows in set (0.00 sec)

(4)这里我要拿到一个in查询的匹配参数,所以使用group_concat来拼接查询结果,使用的时候再在两端拼上“(‘”和"')"就可以啦

mysql> select group_concat(code separator "','") as codes from 
    ->     (select (case when org_code=@r then org_code else null end) as code,
    ->             (case when org_code=@r then @r:=parent_code else null end) as parent
    ->     from (select org_code,parent_code from class order by org_code DESC) as c,(select @r:='000100010001') as t) as tmp 
    -> where code is not null;
+--------------------------------+
| codes                          |
+--------------------------------+
| 000100010001','00010001','0001 |
+--------------------------------+
1 row in set (0.00 sec)

猜你喜欢

转载自www.cnblogs.com/ling-diary/p/9360606.html
今日推荐