原来SQL也能递归
1. WITH
本文还是基于 Postgres13 演示, 在开始讲解递归前首先得介绍下 WITH
,递归是以它为前提的
WITH 语句也叫 CTE
公用表达式,跟我们的临时表差不多(轻量级视图),辅助语句,它可以自引用(最突出的地方就是用作递归),可以多次引用,实现重复利用。
在WITH子句中的每一个辅助语句可以是一个SELECT、INSERT、UPDATE或DELETE,并且WITH子句本身也可以被附加到一个主语句,主语句也可以是SELECT、INSERT、UPDATE或DELETE。
语法示例
1 |
|
- column_name 指定 inner_query_definition_1 的列名(从前往后),可以省略在内部定义,必须保证唯一
- inner_query_definition_1 就是辅助语句,可以是 SELECT 可以是 INSERT 等等
- outer_query_definition 主语句,必须和CTE定义语句同时执行,CTE 是临时虚拟表,只有立即引用它,才是有意义的。
1.1 初始化数据
1 |
|
1 |
|
parent_id 也许不相同,所以需要注意下数据是否准确
1.2 示例
1.2.1 SELECT
1 |
|
这边我们使用 GENERATE_SERIES
函数来进行一定规则的填充模拟月份。需要排序或者多次引用的可以自己尝试,比如自连接
1.2.2 UPDATE
1 |
|
我们可以看到返回的是修改后的数据,需要注意的是 cte 定义的列,必须在结果中返回,否则报错
1.2.3 DELETE
1 |
|
删除后会返回删除的数据,然后我们再去新增哈哈(只是举例子)
1.2.4 INSERT
1 |
|
返回的就是新增的数据。
WITH 辅助语句和主语句都可以是SELECT,INSERT,UPDATE,DELETE中的任何一种语句,除了演示的这几种,还有很多组合,例如定义多个辅助子句,我相信平常工作肯定会有能用得上的场景,自行发挥。
2. Recursive
recursive
是一个 WITH 的一个重要属性,使用 recursive 可以引用自己的输出,就能达到递归的效果了
语法
1 |
|
开始的时候我们初始化了一个地区表,现在我们来看下湖北下面有多少城市
1 |
|
没截完,可以看到查出了湖北有哪些城市,以及城市下面又有哪些城市,这种结构只能靠递归去做,我们不知道下面有多少级。
解释一下上面 sql 的流程,首先是 UNION ALL 上面一部分,刚也说了这个是非递归部分,也就是说只会查一次,是我们的基础数据,把结果集放入 res ,然后
UNION ALL 是用来合并我们多个查询结果集的,稍后再讲解,最后就是下面一部分引用了我们的 res 结果集,然后去关联查,找到相匹配的下级数据,跟之前的 res 合并,一直重复,直到没有匹配的,最后递归结束。
非常适合组织结构,树状结构等等,很完美,需要注意的是跟在代码里面一样不能产生环状,停不下来
UNION ALL 和 UNION 的异同
- 都是合并多个结果集的
- UNION ALL 不去重不排序,UNION 去重排序
- UNION ALL 效率更高
上面是从上往下查,再来一个从下往上查,看一下39浠水县所属上层地区
1 |
|
格式化了一下,最终效果没毛病,使用递归时也有需要注意的地方,语法有要求,一定要尝试才会知道!
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!