AnalyticDB for PostgreSQL 6.0 新特性解析:Recursive CTE (Common Table Expressions)

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介: Recursive CTE (Common Table Expressions) 能够实现SQL的递归查询功能,一般用于处理逻辑上为层次化或树状结构的数据(如查询组织结构、物料清单等),方便对该类数据进行多级递归查询。

作者简介:陈毅能(苇度)毕业于中国科学院,曾任职于百度、微软亚洲研究院、华为、阿里巴巴等公司,专注于分布式数据库内核开发。

Recursive CTE (Common Table Expressions) 能够实现SQL的递归查询功能,一般用于处理逻辑上为层次化或树状结构的数据(如查询组织结构、物料清单等),方便对该类数据进行多级递归查询。与Oracle的CONNECT BY语法的功能类似。

在AnalyticDB for PostgreSQL 6.0版本中,Recursive CTE不再作为待验证特性,而是默认打开。可以通过参数gp_recursive_cte打开或关闭Recursive CTE,默认情况下,gp_recursive_cte是打开的。

show gp_recursive_cte;

 gp_recursive_cte
------------------
 on
(1 row)

例子:1到100求和

使用Recursive CTE可以完成一些普通SQL语句无法完成的功能。使用Recursive CTE后,SQL语句可以引用它自己的输出。首先来看一个例子,计算1、2、……、100的和。

WITH RECURSIVE cte(n) AS (
    VALUES (1)
  UNION ALL
    SELECT n+1 FROM cte WHERE n < 100
)
SELECT sum(n) FROM cte;

 sum
------
 5050
(1 row)

上述例子中,CTE递归调用了自己,从而生成了1到100的序列,进而在主查询中进行求和。

Recursive CTE语法及执行逻辑

使用Recursive CTE的语法如下:

WITH RECURSIVE cte_name AS (
    non_recursive_term
  UNION [ ALL ]
    recursive_term
)
sql_statement;

在recursive_term的部分,Recursive CTE对自身进行自引用。其整体执行逻辑如下:

  • 执行non_recursive_term部分。如果是UNION,还需要执行一次去重。然后将数据作为本轮执行的结果,并将其结果放入一个临时工作表
  • 如果这个临时工作表非空,则循环执行如下步骤。如果这个临时工作表为空,则返回所有轮的执行结果
    (1)执行recursive_term部分。如果是UNION,需要去除重复数据,且要去除和之前结果重复的数据。然后将数据作为本轮执行的结果,并将其结果放入一个中间结果表

(2)将临时工作表的内容替换为中间结果表,并且清空中间结果表

在使用Recursive CTE的时候,需要确保执行结果是可收敛的,即总有一轮的执行结果为空,以结束循环,否则查询将出现无限循环。在前面1到100求和的例子中,有一个WHERE条件限制循环执行100步,数字达到100后因不满足WHERE条件,返回0行数据,循环终止,查询结束。

从上述执行逻辑看,Recursive CTE将对数据进行广度优先遍历。

例子:通过省市上下级关系表查询

建立省市上下级关系表:

CREATE TABLE city_relation
(
    id int           -- 当前省市id
  , parent_id int    -- 上级省市id
  , name varchar(10) -- 当前省市名称
);

插入省市关系数据:

INSERT INTO city_relation values( 2,  NULL, '浙江省');
INSERT INTO city_relation values( 1,  NULL, '广东省');
INSERT INTO city_relation values( 3,  2,    '衢州市');
INSERT INTO city_relation values( 4,  2,    '杭州市');
INSERT INTO city_relation values( 5,  2,    '湖州市');
INSERT INTO city_relation values( 6,  2,    '嘉兴市');
INSERT INTO city_relation values( 7,  2,    '宁波市');
INSERT INTO city_relation values( 8,  2,    '绍兴市');
INSERT INTO city_relation values( 9,  2,    '台州市');
INSERT INTO city_relation values(10,  2,    '温州市');
INSERT INTO city_relation values(11,  2,    '丽水市');
INSERT INTO city_relation values(12,  2,    '金华市');
INSERT INTO city_relation values(13,  2,    '舟山市');
INSERT INTO city_relation values(14,  4,    '上城区');
INSERT INTO city_relation values(15,  4,    '下城区');
INSERT INTO city_relation values(16,  4,    '拱墅区');
INSERT INTO city_relation values(17,  4,    '余杭区');
INSERT INTO city_relation values(18, 11,    '金东区');
INSERT INTO city_relation values(19,  1,    '广州市');
INSERT INTO city_relation values(20,  1,    '深圳市');

查询浙江省及其下属城市列表:

WITH RECURSIVE cities AS 
( 
    SELECT id, name, parent_id, name::text as path FROM city_relation WHERE id=2
  UNION ALL
    SELECT t.id, t.name, t.parent_id, c.path || '>' || t.name as path
    FROM city_relation t JOIN cities c ON t.parent_id = c.id
)
SELECT id, name, path FROM cities;

查询结果:

  id |  name  |         path
----+-------+----------------------
  2 | 浙江省 | 浙江省
 13 | 舟山市 | 浙江省>舟山市
 11 | 丽水市 | 浙江省>丽水市
 10 | 温州市 | 浙江省>温州市
  9 | 台州市 | 浙江省>台州市
  6 | 嘉兴市 | 浙江省>嘉兴市
  5 | 湖州市 | 浙江省>湖州市
 12 | 金华市 | 浙江省>金华市
  8 | 绍兴市 | 浙江省>绍兴市
  7 | 宁波市 | 浙江省>宁波市
  4 | 杭州市 | 浙江省>杭州市
  3 | 衢州市 | 浙江省>衢州市
 18 | 金东区 | 浙江省>丽水市>金东区
 17 | 余杭区 | 浙江省>杭州市>余杭区
 14 | 上城区 | 浙江省>杭州市>上城区
 15 | 下城区 | 浙江省>杭州市>下城区
 16 | 拱墅区 | 浙江省>杭州市>拱墅区
(17 rows)

引用

[1] https://gpdb.docs.pivotal.io/6-0/relnotes/gpdb-60-release-notes.html
[2] https://gpdb.docs.pivotal.io/6-0/admin_guide/query/topics/CTE-query.html
[3] https://blog.csdn.net/zengshaotao/article/details/84753796 (版权不明,互联网上可找到的发表最早的一篇)

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
5月前
|
缓存 编译器 测试技术
PHP 8新特性解析与应用
在软件开发的广阔天地中,PHP始终是一颗耀眼的星辰。随着PHP 8的发布,一系列激动人心的新特性为开发者带来了前所未有的编程体验。本文将深入探讨PHP 8中的JIT编译器、联合类型、命名参数、匹配表达式等关键特性,并通过实例分析它们如何优化代码结构、提升执行效率。我们将一起见证PHP 8如何开启现代化PHP开发的新篇章,并为读者提供实用的技术参考。
43 2
|
3月前
|
SQL 关系型数据库 数据库
PostgreSQL数据库报错 ERROR: multiple default values specified for column "" of table "" 如何解决?
PostgreSQL数据库报错 ERROR: multiple default values specified for column "" of table "" 如何解决?
383 59
|
5月前
|
安全 编译器 测试技术
PHP 8新特性解析与应用实践
本文深入探讨了PHP 8的新颖特性,并结合数据和案例分析,展示了这些新特性如何在实际开发中提升代码质量和执行效率。文章不仅涵盖了语言层面的更新,如JIT编译器和联合类型,还讨论了生态系统中的改进,例如改进的错误处理和性能优化技巧。通过逻辑严密的分析,本文旨在为读者提供一份关于PHP 8升级和应用的全面指南。
40 0
|
5月前
|
存储 SQL 编译器
PHP 8新特性深度解析与实战应用
本文将深入探讨PHP 8的新增特性,并结合实际案例演示如何有效利用这些特性优化现有项目。通过本文,您将了解到PHP 8带来的性能提升、安全性增强以及代码简化等方面的改进,以及如何将这些新特性融入日常开发工作之中。 【7月更文挑战第29天】
55 8
|
5月前
|
缓存 安全 测试技术
深入PHP 7:新特性与性能提升解析
在PHP 7的发布中,我们见证了一系列令人兴奋的性能改进和新特性的加入。本文将深入探讨这些变化如何影响开发者的日常编程实践,并展示通过实际例子如何最大化利用PHP 7的优势。准备好迎接代码效率和开发体验的全新升级!
|
5月前
|
大数据 编译器 API
PHP 7新特性深度解析与应用实践
【7月更文挑战第28天】本文深入探讨PHP 7带来的革新特性,从性能优化到语法改进,逐一剖析其背后的技术原理和实际影响。通过实例展示如何有效利用这些新特性来提升开发效率和代码质量,为PHP开发者提供切实可行的升级和优化策略。
|
5月前
|
数据挖掘 编译器 PHP
PHP 8新特性解析及其对现代Web开发的影响
随着PHP 8的发布,这一广泛使用的服务器端脚本语言带来了一系列创新特性,旨在提升性能、增强语法的易用性以及支持最新的编程范式。本文将深入探讨PHP 8中的JIT编译器、联合类型、匹配表达式等关键特性,并通过实际案例分析它们如何优化代码结构、提高执行效率,并简化日常开发工作,从而全面评估PHP 8对现代Web开发实践的深远影响。
|
5月前
|
安全 编译器 测试技术
PHP 8新特性解析与实践
作为一门历史悠久的脚本语言,PHP在近期发布的PHP 8版本中引入了诸多令人振奋的新特性。本篇文章将深入探讨这些新特性,包括JIT编译器、联合类型、命名参数、匹配表达式等,并结合实际代码示例,展示如何在项目中应用这些新功能来提升开发效率和代码质量。
|
5月前
|
算法 编译器 数据处理
PHP 8新特性深度解析与应用实践
本文旨在深入探讨PHP 8的新增特性,并指导如何将这些特性应用于实际开发中。文章将重点介绍JIT编译器、联合类型、命名参数、匹配表达式等关键改进,并通过实例展示它们如何提升代码性能和可读性。读者将了解到这些特性背后的设计哲学及其对PHP未来发展方向的影响。
43 1
|
5月前
|
安全 编译器 数据处理
PHP 8:新特性解析与实践应用
本文深入探讨了PHP 8版本中引入的关键新特性,包括JIT编译器、联合类型、命名参数、匹配表达式等,并结合实例代码演示了如何在实际项目中有效利用这些新功能来提高开发效率和代码质量。通过对比分析PHP 7与PHP 8的性能差异,文章进一步验证了新版本带来的性能提升,旨在为PHP开发者提供升级至PHP 8的全面指南。
55 2

相关产品

  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多