PostGreSQL开窗函数

  • Post author:
  • Post category:其他

PostGreSQL开窗函数

语法
<窗口函数>
over(partition by 分组列 order by 排序列)
order by 并非必要

over() 是开窗函数的关键词

窗口函数存在哪些 ?

聚合类:sum() avg() max() min() count()

内置函数:RANK DENSE_RANK ROW_NUMBER等等

聚合类的窗口函数使用方法和平时使用相同

以sum()为例

id	type	name	amount
1	 1		liliya	3600
2	 1		will	4500
3	 2		hell	2350

select 
id,
name,
amount,
sum(amount)over(partiton by type) as total_amount

结果
id 	name 	amount 	total_amount
1	liliya	3600	8100
2	will	4500	8100
3	hell	2350	2350

内置函数:RANK,DENSE_RANK,ROW_NUMBER

三者性质相同,都是对数据进行排序并且编号,不过结果存在些许的差异

以RANK为例

table name -> t1
id	type	name	amount
1	 1		liliya	3600
2	 1		will	4500
3	 2		hell	2350
4	 1		oldman	2300
5	 2		trueman	4610
6	 2		ora		2350

select 
rank()over(partition by type order by amount desc),* from t1

结果就是
rank	id	type	name	amount
1		2	 1		will	 4500
2		1	 1		liliya	 3600
3		4	 1		oldman	 2300
1		5	 2		trueman	 4610
2		3 	 2		hell	 2350
3		6	 2		ora		 2350

RANK 使用结果有一个特点,就是若是排序的数据相同,则标记为并列,并且下一条数据的标记会 跳过标记相同的个数,进行标记 就比如并列第一的存在3个,name这三个标记为1 从第4个标记开始,标记为4 而非2

DENSE_RANK 则是不会跳过重复的个数,而是顺延标记。

ROW_NUMBER 不管重复,直接从1开始进行标记

开窗函数的使用,是因为group by 使用过程中,所select 的列都必须在group by中,这个会在实际中存在诸多麻烦,而开窗函数可以很好的避免此类情况。

同时开窗函数适用于TOPN 十分的方便

本人实际应用开窗函数的情况

table_name -> t1
自增ID	订单号	流水号	流水金额	流水收款日期
id	order_id	fina_id	amount	date
1	123			 t1		 30		2020-05-30
2	123			 t2		 100	2020-05-31
3	123			 t3		 500	2020-06-05
4	123			 t4		 70		2020-07-01

需求:累计金额首次超过300 的那天标注为1 
需求的结果表
order_id	fina_id	amount	date			sum_amount		is_sign
123			 t1		 30		2020-05-30			30				0
123			 t2		 100	2020-05-31			130				0
123			 t3		 500	2020-06-05			630				1
123			 t4		 70		2020-07-01			700				0
SQL:
select 
order_id,
fina_id,
amount,
date,
sum(amount)over(partition by order_id order by date) as sum_amount
case when sum(amount)over(partition by order_id order by date) >300 then 1 else 0 end as is_sign
from t1
此时得到的结果是
order_id	fina_id	amount	date			sum_amount		is_sign
123			 t1		 30		2020-05-30			30				0
123			 t2		 100	2020-05-31			130				0
123			 t3		 500	2020-06-05			630				1
123			 t4		 70		2020-07-01			700				1
还未符合我们想要的结果
将上表 给个别名 t2
SQL:
select 
order_id,
fina_id,
amount,
date,
sum_amount,
sum(is_sign)over(partition by order_id order by date) as sum_sign
from t2
此时得到的结果是:
order_id	fina_id	amount	date			sum_amount		sum_sign
123			 t1		 30		2020-05-30			30				0
123			 t2		 100	2020-05-31			130				0
123			 t3		 500	2020-06-05			630				1
123			 t4		 70		2020-07-01			700				2
尚未符合要求 将上表命名别名 t3
select 
order_id,
fina_id,
amount,
date,
sum_amount,
case when sum_sign = 1 then 1 else 0 end as is_sign
from t3
自此得到最终的结果表
order_id	fina_id	amount	date			sum_amount		is_sign
123			 t1		 30		2020-05-30			30				0
123			 t2		 100	2020-05-31			130				0
123			 t3		 500	2020-06-05			630				1
123			 t4		 70		2020-07-01			700				0

之所以要这种形式,是因为要根据查询时间计算转化人数,当累计金额大于300时,才算上一次人数,而后其他则不再计算

这个方法是我个人所做,不知道有没有更加简便的方法,希望有更加简便方法的朋友,可以告知,谢谢


版权声明:本文为Qian_Qu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。