postgresql的WITH RECURSIVE实现递归

本文深入解析 SQL 中的 CTE (公共表表达式)概念,演示如何使用 with as 语句暂存结果集,以及如何进行递归查询以遍历组织结构。通过具体实例,展示 CTE 在处理复杂数据关系时的强大能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://www.jasongj.com/sql/cte/

with as可以把结果集暂存,下面两个sql的结果是一样的(顺序不一样)

with r1 as (select * from users),r2 as (select * from employees)
select r2.* from r1 inner join  r2 on r1.user_pk=r2.user_pk 
where r1.user_type<>'1'
select employees.* from users inner join employees on users.user_pk=employees.user_pk 
where users.user_type<>'1'

递归查询

组织表有如下数据:
id=10的数据的亲(上级)组织的id是70645

countidpidname
121070645組織10
1270635null組織1
1270645null組織9
127063670635組織2
127063770636組織3
127063870637組織4
127063970638組織5
127064070635組織6
127064170640組織7
1271113null組職名
1221001null組織名(日)01
1220002null組織名(日)02
WITH RECURSIVE results AS
(
  SELECT
    id,pid,name
  FROM  organizations
  WHERE id = 70639
  UNION ALL			--注释all可以去重
  SELECT
    org.id,org.pid,org.name
	FROM results
  inner JOIN organizations org
  ON results.pid = org.id
)
SELECT
  count(1) over(),*
FROM results;

上面的sql可以查询id = 70639的组织和其所有亲组织,结果如下

countidpidname
57063970638組織5
57063870637組織4
57063770636組織3
57063670635組織2
570635null組織1
--可能报错type character varying overall,加上::varchar(100)统一字段类型
WITH RECURSIVE results AS
(
  SELECT
    id,pid,name::varchar(100),1 num
  FROM  organizations
	where pid is null
  UNION ALL
  SELECT
    org.id,org.pid,(results.name||'>'||org.name)::varchar(100) name,1+results.num num
	FROM results
  inner JOIN organizations org
	ON results.id = org.pid
	--where results.num<3
)
SELECT
  count(1) over(),*
FROM results;

上面的sql可以从上往下(广度优先)查询所有组织,num是当前组织的层数,结果如下

countidpidnamenum
1270635null組織11
1270645null組織91
1271113null組職名1
1221001null組織名(日)011
1220002null組織名(日)021
127064070635組織1>組織62
127063670635組織1>組織22
121070645組織9>組織102
127064170640組織1>組織6>組織73
127063770636組織1>組織2>組織33
127063870637組織1>組織2>組織3>組織44
127063970638組織1>組織2>組織3>組織4>組織55

如果只需要检索最上面3层的组织,加上where results.num<3即可,结果如下

countidpidnamenum
1070635null組織11
1070645null組織91
1071113null組職名1
1021001null組織名(日)011
1020002null組織名(日)021
107064070635組織1>組織62
107063670635組織1>組織22
101070645組織9>組織102
107064170640組織1>組織6>組織73
107063770636組織1>組織2>組織33

WITH RECURSIVE 执行过程 从上面的例子可以看出,WITH RECURSIVE语句包含了两个部分
non-recursive term(非递归部分),即上例中的union all前面部分 recursive
term(递归部分),即上例中union all后面部分 执行步骤如下

执行non-recursive term。(如果使用的是union而非union all,则需对结果去重)
其结果作为recursive term中对result的引用,同时将这部分结果放入临时的working table中
重复执行如下步骤,直到working table为空:
用working table的内容替换递归的自引用,执行recursive term,
(如果使用union而非union all,去除重复数据),
并用该结果(如果使用union而非union all,则是去重后的结果)替换working table

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值