PostgreSQL 递归查询简析

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: ### 语法```plsqlWITH RECURSIVE cte_name AS(    CTE_query_definition -- 非递归项    UNION [ALL]    CTE_query definion -- 递归项) SELECT * FROM cte_name;```递归 WITH 查询的一般形式始终是非递归项,然后是 UNION(或 UNION ALL),

语法

WITH RECURSIVE cte_name AS(
    CTE_query_definition -- 非递归项
    UNION [ALL]
    CTE_query definion  -- 递归项
) SELECT * FROM cte_name;

递归 WITH 查询的一般形式始终是非递归项,然后是 UNION(或 UNION ALL),然后是递归项,其中只有递归项可以包含对查询自身输出的引用。

  1. 非递归项:非递归项是一个 CTE 查询定义,它构成了 CTE 结构的基本结果集。
  2. 递归项:递归项是使用 UNION 或 UNION ALL 运算符与非递归项连接的一个或多个 CTE 查询定义。递归术语引用 CTE 名称本身。
  3. 终止检查:当前一次迭代没有返回任何行时,递归停止。

PostgreSQL 按以下顺序执行递归 CTE:

  1. 执行非递归项以创建基本结果集 (R0)。
  2. 以Ri为输入执行递归项,返回结果集Ri+1作为输出。
  3. 重复步骤 2,直到返回一个空集。 (终止检查)
  4. 返回结果集 R0, R1, ... Rn 的 UNION 或 UNION ALL 的最终结果集

例子

  • 创建表
CREATE TABLE employees (
    employee_id serial PRIMARY KEY,
    full_name VARCHAR NOT NULL,
    manager_id INT
);

员工表包含三列:employee_id、manager_id 和 full_name。 manager_id 列指定员工的经理 ID。

  • 插入数据
INSERT INTO employees (
    employee_id,
    full_name,
    manager_id
)
VALUES
    (1, 'Michael North', NULL),
    (2, 'Megan Berry', 1),
    (3, 'Sarah Berry', 1),
    (4, 'Zoe Black', 1),
    (5, 'Tim James', 1),
    (6, 'Bella Tucker', 2),
    (7, 'Ryan Metcalfe', 2),
    (8, 'Max Mills', 2),
    (9, 'Benjamin Glover', 2),
    (10, 'Carolyn Henderson', 3),
    (11, 'Nicola Kelly', 3),
    (12, 'Alexandra Climo', 3),
    (13, 'Dominic King', 3),
    (14, 'Leonard Gray', 4),
    (15, 'Eric Rampling', 4),
    (16, 'Piers Paige', 7),
    (17, 'Ryan Henderson', 7),
    (18, 'Frank Tucker', 8),
    (19, 'Nathan Ferguson', 8),
    (20, 'Kevin Rampling', 8);
  • 查询员工id为2的经理的所有下属
WITH RECURSIVE subordinates(employee_id, full_name, manager_id) AS (
    SELECT
        employee_id,
        manager_id,
        full_name
    FROM
        employees
    WHERE
        employee_id = 2
    UNION
        SELECT
            e.employee_id,
            e.manager_id,
            e.full_name
        FROM
            employees e, subordinates s
        WHERE
          s.employee_id = e.manager_id
) SELECT * FROM subordinates;

结果

 employee_id | full_name |   manager_id
-------------+-----------+-----------------
           2 |         1 | Megan Berry
           6 |         2 | Bella Tucker
           7 |         2 | Ryan Metcalfe
           8 |         2 | Max Mills
           9 |         2 | Benjamin Glover
          16 |         7 | Piers Paige
          17 |         7 | Ryan Henderson
          18 |         8 | Frank Tucker
          19 |         8 | Nathan Ferguson
          20 |         8 | Kevin Rampling
(10 rows)

这个过程是怎么工作的呢?

  1. 先执行非递归项,获取基础结果集R0:
postgres=> SELECT employee_id, manager_id, full_name FROM employees WHERE employee_id = 2;

 employee_id | manager_id |  full_name
-------------+------------+-------------
           2 |          1 | Megan Berry
(1 row)
  1. 把基础结果集 R0 作为临时表 subordinates 的查询结果,执行递归项,获取结果集R1:
postgres=> select employee_id, manager_id, full_name from employees e, subordinates s where s.employee_id = e.manager_id;

 employee_id |    full_name    | manager_id
-------------+-----------------+------------
           6 | Bella Tucker    |          2
           7 | Ryan Metcalfe   |          2
           8 | Max Mills       |          2
           9 | Benjamin Glover |          2
(4 rows)
  1. 把结果集 R1 作为临时表 subordinates 的查询结果,执行递归项,获取结果集R2:
postgres=> select employee_id, manager_id, full_name from employees e, subordinates s where s.employee_id = e.manager_id;

 employee_id |    full_name    | manager_id
-------------+-----------------+------------
          16 | Piers Paige     |          7
          17 | Ryan Henderson  |          7
          18 | Frank Tucker    |          8
          19 | Nathan Ferguson |          8
          20 | Kevin Rampling  |          8
(5 rows)
  1. 重复步骤 2-3,直到递归项的结果集 Rn 为空,退出循环,并把 R0, R1, ... Rn 的 UNION 或 UNION ALL 之后作为最终结果集返回。

注意:UNION 会丢弃重复的行和重复任何先前结果行的行,UNION ALL 保留所有行。

参考:https://www.postgresqltutorial.com/postgresql-recursive-query/

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
消息中间件 存储 关系型数据库
PostgreSQL技术大讲堂 - 第33讲:并行查询管理
PostgreSQL从小白到专家,技术大讲堂 - 第33讲:并行查询管理
473 1
|
7月前
|
存储 关系型数据库 数据库
postgresql|数据库|提升查询性能的物化视图解析
postgresql|数据库|提升查询性能的物化视图解析
743 0
|
SQL 关系型数据库 Go
PostgreSQL 查询语句大全
PostgreSQL 查询语句大全
113 0
|
1月前
|
SQL 关系型数据库 数据库
PostgreSQL性能飙升的秘密:这几个调优技巧让你的数据库查询速度翻倍!
【10月更文挑战第25天】本文介绍了几种有效提升 PostgreSQL 数据库查询效率的方法,包括索引优化、查询优化、配置优化和硬件优化。通过合理设计索引、编写高效 SQL 查询、调整配置参数和选择合适硬件,可以显著提高数据库性能。
366 1
|
4月前
|
缓存 关系型数据库 数据库
PostgreSQL 查询性能
【8月更文挑战第5天】PostgreSQL 查询性能
88 8
|
6月前
|
SQL 关系型数据库 数据库
Python执行PostgreSQL数据库查询语句,并打印查询结果
本文介绍了如何使用Python连接和查询PostgreSQL数据库。首先,确保安装了`psycopg2`库,然后创建数据库连接函数。接着,展示如何编写SQL查询并执行,例如从`employees`表中选取所有记录。此外,还讨论了处理查询结果、格式化输出和异常处理的方法。最后,提到了参数化查询和事务处理以增强安全性及确保数据一致性。
Python执行PostgreSQL数据库查询语句,并打印查询结果
|
5月前
|
Java 关系型数据库 API
使用Spring Boot和PostgreSQL构建高级查询
使用Spring Boot和PostgreSQL构建高级查询
|
6月前
|
SQL 关系型数据库 数据库
Python查询PostgreSQL数据库
木头左教你如何用Python连接PostgreSQL数据库:安装`psycopg2`库,建立连接,执行SQL脚本如创建表、插入数据,同时掌握错误处理和事务管理。别忘了性能优化,利用索引、批量操作提升效率。下期更精彩!💡 csvfile
Python查询PostgreSQL数据库
|
7月前
|
SQL 人工智能 Oracle
PostgreSQL 递归查询(含层级和结构)
PostgreSQL 递归查询(含层级和结构)
|
存储 NoSQL 关系型数据库
深入探索地理空间查询:如何优雅地在MySQL、PostgreSQL及Redis中实现精准的地理数据存储与检索技巧
深入探索地理空间查询:如何优雅地在MySQL、PostgreSQL及Redis中实现精准的地理数据存储与检索技巧
2202 0