背景:
开窗函数不论是spark的还是clickhouse的在日常的查询中是一个很常用的功能,特别是他想要解决的问题和group by的很类似,这两种容易引起混淆,本文就简单的描述下开窗函数的简单用法
使用详解
首先窗口函数和group by是完全没有交集的,他们完全没有任何关系,group by聚合数据后会导致行数合并减少,但是窗口函数不会新增行,也不会减少行,这也就意味着对于每一行,窗口函数只是附加了新的一列数据,意识到这一点很重要
其次窗口函数的执行计划就是在每条sql的最后,仅仅只是在最终的order by之前执行,所以也就意味着他不会改变最终结果的行数,仅仅是追加新的一列数据
我们来看看具体的用法:
window_function (expression) OVER (
[ PARTITION BY part_list ]
[ ORDER BY order_list ]
[ { ROWS | RANGE } BETWEEN frame_start AND frame_end ] )
window函数主要包括以下几类:
聚合函数:AVG(), COUNT(), MIN(), MAX(), SUM()
分析函数:FIRST_VALUE(), LAST_VALUE(), LEAD(), LAG()
排序函数:RANK(), DENSE_RANK(), ROW_NUMBER()
ROWS关键字是选择当前行的前后几行,例如 ROWS BETWEEN 5 PRECEDING AND 3 FOLLOWING 表示往前 5 行到往后 3 行,一共 9 行数据,注意这只是选择行数据作为窗口函数应用的范围,比如这9行数据应用Min函数,对于每一条记录来说应用窗口函数后只会得到一个结果,比如这里的最小值,我们以获取一个每个学生最高的top2学科作为例子,假设每个学生都参与五门考试,记录学生成绩的表如下
create table student{
stu_no String,
course String
score int
}
我们想要获取每个学生最高的两门学科的成绩,我们利用开窗函数怎么得到呢?
select stu_no,course,score from
(select stu_no,course, score,row_number() over(PARTITION BY stu_no order by score) as row_num
from student) as a
where row_num <= 2;
或者
select stu_no,course,score from
(select stu_no,course, score,row_number() over(PARTITION BY stu_no order by score ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as row_num
from student) as a
where row_num <= 2
上面这两个sql是等价的,都可以得到每个学生分数最高的两门课程
备注: 窗口函数和group by想要解决的问题具有相似性,不过从用法角度来看,这两者没有任何交集,窗口函数会作用于group by的最终结果之上,也就是在select 之后,在最终返回结果之前