欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

教你如何使用MySQL8递归的方法

程序员文章站 2023-11-02 10:52:58
之前写过一篇 mysql通过自定义函数的方式,递归查询树结构,从mysql 8.0 开始终于支持了递归查询的语法 cte 首先了解一下什么是 cte,全名 common t...

之前写过一篇 mysql通过自定义函数的方式,递归查询树结构,从mysql 8.0 开始终于支持了递归查询的语法

cte

首先了解一下什么是 cte,全名 common table expressions

with
 cte1 as (select a, b from table1),
 cte2 as (select c, d from table2)
select b, d from cte1 join cte2
where cte1.a = cte2.c;

cte1, cte2 为我们定义的cte,可以在当前查询中引用

可以看出 cte 就是一个临时结果集,和派生表类似,二者的区别这里不细说,可以参考下mysql开发文档:

递归查询

先来看下递归查询的语法

with recursive cte_name as
(
  select ...   -- return initial row set
  union all / union distinct
  select ...   -- return additional row sets
)
select * from cte;
  • 定义一个cte,这个cte 最终的结果集就是我们想要的 ”递归得到的树结构",recursive 代表当前 cte 是递归的
  • 第一个select 为 “初始结果集”
  • 第二个select 为递归部分,利用 "初始结果集/上一次递归返回的结果集" 进行查询得到 “新的结果集”
  • 直到递归部分结果集返回为null,查询结束
  • 最终union all 会将上述步骤中的所有结果集合并(union distinct 会进行去重),再通过 select * from cte; 拿到所有的结果集

递归部分不能包括:

  • 聚合函数例如 sum()
  • group by
  • order by
  • limit
  • distinct

上面的讲解可能有点抽象,通过例子慢慢来理解

with recursive cte (n) as -- 这里定义的n相当于结果集的列名,也可在下面查询中定义
(
 select 1
 union all
 select n + 1 from cte where n < 5
)
select * from cte;


-- result
+------+
| n  |
+------+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+------+

  • 初始结果集为 n =1
  • 这时候看递归部分,第一次执行 cte结果集即是 n =1,条件发现并不满足 n < 5,返回 n + 1
  • 第二次执行递归部分,cte结果集为 n = 2,递归... 直至条件不满足
  • 最后合并结果集

example

最后来看一个树结构的例子

create table `c_tree` (
 `id` int(11) not null auto_increment,
 `cname` varchar(255) collate utf8mb4_unicode_ci default null,
 `parent_id` int(11) default null,
 primary key (`id`)
) engine=innodb auto_increment=13 default charset=utf8mb4 collate=utf8mb4_unicode_ci;
mysql> select * from c_tree;
+----+---------+-----------+
| id | cname  | parent_id |
+----+---------+-----------+
| 1 | 1    |     0 |
| 2 | 2    |     0 |
| 3 | 3    |     0 |
| 4 | 1-1   |     1 |
| 5 | 1-2   |     1 |
| 6 | 2-1   |     2 |
| 7 | 2-2   |     2 |
| 8 | 3-1   |     3 |
| 9 | 3-1-1  |     8 |
| 10 | 3-1-2  |     8 |
| 11 | 3-1-1-1 |     9 |
| 12 | 3-2   |     3 |
+----+---------+-----------+
mysql> 
with recursive tree_cte as
(
  select * from c_tree where parent_id = 3
  union all
  select t.* from c_tree t inner join tree_cte tcte on t.parent_id = tcte.id
)
select * from tree_cte;
+----+---------+-----------+
| id | cname  | parent_id |
+----+---------+-----------+
| 8 | 3-1   |     3 |
| 12 | 3-2   |     3 |
| 9 | 3-1-1  |     8 |
| 10 | 3-1-2  |     8 |
| 11 | 3-1-1-1 |     9 |
+----+---------+-----------+
  • 初始结果集r0 = select * from c_tree where parent_id = 3
  • 递归部分,第一次 r0 与 c_tree inner join 得到 r1
  • r1 再与 c_tree inner join 得到 r2
  • ...
  • 合并所有结果集 r0 + ... + ri

更多信息


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。