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;
该语句书写包括如下几步
- 设定递归语法,首先初始执行第一句
SELECT 1
,也可以写成select xxx from xxx where xxx
- 其结果给到n,当n值发生改变,就会执行:
SELECT n + 1 FROM cte WHERE n < 5
- 最终结果给到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;
该语句执行解析如下
- 先设定开始的条件为父ID为空,即所有的父节点
select administrative_division_sn sn, parent_administrative_division_sn pSn, name from administrative_division2 ad where parent_administrative_division_sn is null
- 设置循环的条件为等于这个父节点的子节点
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
- 执行完2此时的res.sn就等于子sn了,然后递归执行2
- 最终执行
set ad.full_name=t1.name where ad.administrative_division_sn=t1.sn
把名称赋值为2中的拼接了的名称concat(res.name, ad2.name)