怎么在group by分组后获取其他列的数据(窗口函数)

一.窗口函数有什么用

聚合函数对结果集进行计算并且通常只返回一行,只会返回聚合的结果和聚合的那列。如果需要返回聚合列之外的列的结果则可以使用窗口函数。窗口函数也是基于结果集计算,与聚合函数不同的是窗口函数会把计算后的结果合并到原来的结果集上,返回多行并保持与结果集相同的行数。

可以使用窗口函数的业务场景:

排名问题:比如每个部门按业绩来排名
topN问题:比如找出每个部门排名前N的员工进行奖励

二.窗口函数语法

除了pg内置的窗口函数rank(),dense_rank(), row_numbe(),lag()等,聚合函数或自定函数接OVER也可作为窗口函数。

窗口函数需要放在SELECT子句中,SQL中语法如下:

<窗口函数> OVER(PARTITION BY <分组列名> ORDER BY <排序列名>)

SQLAlchemy 下可以这样使用:
在这里插入图片描述

三.窗口函数怎么用

1.排名问题
如下学生成绩表(stu_score):

stu_idclassscore
0001190
0002165
0003270
0004165
0005280
0006375
0007395

使用窗口函数取每个班级内按成绩的排名:

SELECT 
	*, 
  RANK() OVER(PARTITION BY class ORDER BY score DESC) AS ranking 
 FROM stu_score;

结果为:

stu_idclassscoreranking
00011901
00021652
00041652
00052801
00032702
00073951
00063752

2.topN问题
取学生成绩表每个班成绩排名第一的学生:

SELECT * 
FROM
	(SELECT *, ROW_NUMBER() OVER (
    PARTITION BY class ORDER BY score DESC
  ) AS ranking FROM stu_score) t1 
WHERE ranking = 1;

结果:

stu_idclassscoreranking
00011901
00052801
00073951

3.举一个实际中遇到的问题是怎么用窗口函数解决的
场景是,现在有一个表有user_id(用户id)、log_date(记录日期)和其他信息,需要把一批用户最新的记录日期的那条记录取出来并且能获取其他信息。
有内味了,这不就是topN问题。具体思路就是按user_id分组,log_date排倒叙取第一条。解决如下:

SELECT * 
FROM
	(SELECT *, ROW_NUMBER() OVER (
    PARTITION BY user_id ORDER BY log_date DESC
  ) AS log_date_rank FROM TABLE) t1 
WHERE log_date_rank = 1;

3.rank、dense_rank、row_number区别

rank 是正常排序,当并列时行号重复,并且产生行号间隙。
dense_rank 是紧密排序,当并列时行号重复,但是不产生间隙,依然按自然数顺延。
row_number 是行数排序,不考虑并列的情况,按照行数依次排序。

四.总结

1)窗口函数同时具有分组(partition by)和排序(order by)的功能。
2)不会改变结果集的行数,可以取到所有列的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值