mysql with recursive 递归用法

with recursive 是一个递归的查询子句,他会把查询出来的结果再次代入到查询子句中继续查询。

语法:

WITH RECURSIVE  cte_name  AS ( 
	初始语句(非递归部分) 
	UNION ALL 
	递归部分语句
)
[ SELECT| INSERT | UPDATE | DELETE]

例子1:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;

在这里插入图片描述
该语句书写包括如下几步

  1. 设定递归语法,首先初始执行第一句SELECT 1,也可以写成select xxx from xxx where xxx
  2. 其结果给到n,当n值发生改变,就会执行:SELECT n + 1 FROM cte WHERE n < 5
  3. 最终结果给到n输出

注意:WITH AS () 后面必须跟着 [ SELECT| INSERT | UPDATE | DELETE] 语句,否则报错。

例子2:

有如下行政区划表

create table administrative_division2
(
    administrative_division_sn        bigint            not null comment '行政区划代码'
        primary key,
    parent_administrative_division_sn bigint            null comment '上级行政区划代码',
    status                            tinyint default 1 not null comment '状态',
    name                              varchar(28)       not null comment '名称*',
    full_name                         varchar(200)      null comment '行政区划全路径名称,省市县全路径名称'
)
    comment '行政区划';

INSERT INTO administrative_division2 (administrative_division_sn, parent_administrative_division_sn, status, name, full_name) VALUES (110000, null, 1, '北京市', '');
INSERT INTO administrative_division2 (administrative_division_sn, parent_administrative_division_sn, status, name, full_name) VALUES (110100, 110000, 1, '北京市市辖区', '');
INSERT INTO administrative_division2 (administrative_division_sn, parent_administrative_division_sn, status, name, full_name) VALUES (110101, 110100, 1, '东城区', '');
INSERT INTO administrative_division2 (administrative_division_sn, parent_administrative_division_sn, status, name, full_name) VALUES (110102, 110100, 1, '西城区', '');
INSERT INTO administrative_division2 (administrative_division_sn, parent_administrative_division_sn, status, name, full_name) VALUES (110105, 110100, 1, '朝阳区', '');

在这里插入图片描述
我们想补充full_name的值变成如下
在这里插入图片描述
那么可以用如下语句

update administrative_division2 ad,(
    with recursive res as (select administrative_division_sn sn, parent_administrative_division_sn pSn, name
                                       from administrative_division2 ad
                                       where parent_administrative_division_sn is null 
                                       union
                                       select ad2.administrative_division_sn as     sn,
                                              ad2.parent_administrative_division_sn pSn,
                                              concat(res.name, ad2.name)     as     name
                                       from res
                                                inner join administrative_division2 ad2
                                                           on res.sn = ad2.parent_administrative_division_sn)
    select * from res
    ) as t1 set ad.full_name=t1.name where ad.administrative_division_sn=t1.sn;

该语句执行解析如下

  1. 先设定开始的条件为父ID为空,即所有的父节点
select administrative_division_sn sn, parent_administrative_division_sn pSn, name from administrative_division2 ad where parent_administrative_division_sn is null
  1. 设置循环的条件为等于这个父节点的子节点
select ad2.administrative_division_sn as sn, ad2.parent_administrative_division_sn pSn, concat(res.name, ad2.name) as name from res inner join administrative_division2 ad2 on res.sn = ad2.parent_administrative_division_sn
  1. 执行完2此时的res.sn就等于子sn了,然后递归执行2
  2. 最终执行set ad.full_name=t1.name where ad.administrative_division_sn=t1.sn把名称赋值为2中的拼接了的名称concat(res.name, ad2.name)

猜你喜欢

转载自blog.csdn.net/qq32933432/article/details/128778680