postgresql——WITH RECURSIVE

前言

RECURSIVE,递归查询。他将WITH从单纯的句法便利变成了一种在标准SQL中不能完成的特性。通过使用RECURSIVE,一个WITH查询可以引用它自己的输出。

准备工作

CREATE TABLE "resource" (
  "id" int4 NOT NULL constraint resource_pk primary key,
  "name" text,
  "parent_id" int4
);

INSERT INTO "public"."resource" VALUES (1, '系统管理', 0);
INSERT INTO "public"."resource" VALUES (2, '基础数据管理', 0);
INSERT INTO "public"."resource" VALUES (3, '组织管理', 1);
INSERT INTO "public"."resource" VALUES (5, '题目管理', 2);
INSERT INTO "public"."resource" VALUES (4, '公司管理', 3);

这是一个无限等级的菜单栏列表。

实验

WITH RECURSIVE res AS (
    SELECT id, name, parent_id
    FROM resource 
    WHERE id = 4
    UNION
    SELECT rr.id,
           rr.name || ' > ' || r.name,
           rr.parent_id
    FROM res r INNER JOIN resource rr ON rr.id = r.parent_id
)
select * from res;

结果:
在这里插入图片描述
递归查询过程
1、计算非递归项。对UNION(但不对UNION ALL),抛弃重复行。把所有剩余的行包括在递归查询的结果中,并且也把它们放在一个临时的工作表中。
2、只要工作表不为空,重复下列步骤:

  • 计算递归项,用当前工作表的内容替换递归自引用。对UNION(不是UNION ALL),抛弃重复行以及那些与之前结果行重复的行。将剩下的所有行包括在递归查询的结果中,并且也把它们放在一个临时的中间表中。
  • 用中间表的内容替换工作表的内容,然后清空中间表。

拆解分析
可以分成两部分:
① non-recursive term(非递归部分),即上例中的union前面部分
② recursive term(递归部分),即上例中union后面部分

1、执行非递归部分

SELECT id, name, parent_id
FROM resource 
WHERE id = 4

结果集和working table4 | 公司管理 |  3

2、执行递归部分,如果是UNION,要用当前查询的结果和上一个working table的结果进行去重,然后放到到临时表中。然后把working table的数据替换成临时表里面的数据。

SELECT rr.id,
       rr.name || ' > ' || r.name,
       rr.parent_id
FROM res r INNER JOIN resource rr ON rr.id = r.parent_id

结果集和working table3 | 组织管理 > 公司管理 |  1

3、同2,直到数据表中没有数据。

SELECT rr.id,
       rr.name || ' > ' || r.name,
       rr.parent_id
FROM res r INNER JOIN resource rr ON rr.id = r.parent_id

结果集和working table1 | 系统管理 > 组织管理 > 公司管理 | 0

4、结束递归,将前几个步骤的结果集合并,即得到最终的WITH RECURSIVE的结果集

WITH RECURSIVE 使用限制

1、 如果在recursive term中使用LEFT JOIN,自引用必须在“左”边
2、 如果在recursive term中使用RIGHT JOIN,自引用必须在“右”边
3、 recursive term中不允许使用FULL JOIN
4、 recursive term中不允许使用GROUP BY和HAVING
5、 不允许在recursive term的WHERE语句的子查询中使用CTE的名字
6、 不支持在recursive term中对CTE作aggregation
7、 recursive term中不允许使用ORDER BY
8、 LIMIT / OFFSET不允许在recursive term中使用
9、 FOR UPDATE不可在recursive term中使用
10、 recursive term中SELECT后面不允许出现引用CTE名字的子查询
11、 同时使用多个CTE表达式时,不允许多表达式之间互相访问(支持单向访问)
12、 在recursive term中不允许使用FOR UPDATE

总结

recursive是pgsql中提供的一种递归的机制,比如当我们查询一个完整的树形结构使用这个就很完美,但是我们应该避免发生递归的死循环,也就是数据的环状。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值