参考来自某乎
数据分析|SQL窗口函数最全使用指南 https://zhuanlan.zhihu.com/p/120269203
通俗易懂的学会:SQL窗口函数 https://zhuanlan.zhihu.com/p/92654574

一.窗口函数有什么用?
在日常工作中,经常会遇到需要在每组内排名,比如下面的业务需求:

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

面对这类需求,就需要使用sql的高级功能窗口函数了。

二.什么是窗口函数?

窗口函数,也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据库数据进行实时分析处理。

窗口函数的基本语法如下:

<窗口函数> over (partition by <用于分组的列名>
                 order by <用于排序的列名>)

每个班内按成绩排名:partition by 班 order by 成绩
给每个学生的课程成绩排名:partition by 学生 order by 课程成绩

那么语法中的<窗口函数>都有哪些呢?

1)一些专用的窗口函数
序号函数:row_number() / rank() / dense_rank()
分布函数:percent_rank() / cume_dist()
前后函数:lag() / lead()
头尾函数:first_val() / last_val()
其他函数:nth_value() / 用途:将分区中的有序数据分为n个桶,记录桶号。
2)原有的聚合函数也可用作窗口函数,如sum(),avg(),count(),max(),min()

三.如何使用窗口函数

接下来,就结合实例,给大家介绍几种窗口函数的用法。

1.专用窗口函数rank

例如下图,是班级表中的内容

sql server窗口函数 sql窗口函数是什么_sql


如果我们想在每个班级内按成绩排名,得到下面的结果。

sql server窗口函数 sql窗口函数是什么_数据库_02


以班级“1”为例,这个班级的成绩“95”排在第1位,这个班级的“83”排在第4位。上面这个结果确实按我们的要求在每个班级内,按成绩排名了。

得到上面结果的sql语句代码如下:

select *,
   rank() over (partition by 班级
                 order by 成绩 desc) as ranking
from 班级表

我们来解释下这个sql语句里的select子句。rank是排序的函数。要求是“每个班级内按成绩排名”,这句话可以分为两部分

1)每个班级内:按班级分组

partition by用来对表分组。在这个例子中,所以我们指定了按“班级”分组(partition by 班级)

2)按成绩排名

order by子句的功能是对分组后的结果进行排序,默认是按照升序(asc)排列。在本例中(order by 成绩 desc)是按成绩这一列排序,加了desc关键词表示降序排列。

通过下图,我们就可以理解partiition by(分组)和order by(在组内排序)的作用了。

sql server窗口函数 sql窗口函数是什么_sql server窗口函数_03


窗口函数具备了我们之前学过的group by子句分组的功能和order by子句排序的功能。那么,为什么还要用窗口函数呢?这是因为,group by分组汇总后改变了表的行数,一行只有一个类别。而partiition by和rank函数不会减少原表中的行数。例如下面统计每个班级的人数。

sql server窗口函数 sql窗口函数是什么_窗口函数_04


相信通过这个例子,你已经明白了这个窗口函数的使用:

select *,
   rank() over (partition by 班级
                 order by 成绩 desc) as ranking
from 班级表

现在我们说回来,为什么叫“窗口”函数呢?这是因为partition by分组后的结果称为“窗口”,这里的窗口不是我们家里的门窗,而是表示“范围”的意思。

简单来说,窗口函数有以下功能:

1)同时具有分组和排序的功能

2)不减少原表的行数

3)语法如下:

<窗口函数> over (partition by <用于分组的列名>
                order by <用于排序的列名>)

2.其他专用窗口函数

rank函数:这个例子中是5位,5位,5位,8位,也就是如果有并列名次的行,会占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,4。

dense_rank函数:这个例子中是5位,5位,5位,6位,也就是如果有并列名次的行,不占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,2。

row_number函数:这个例子中是5位,6位,7位,8位,也就是不考虑并列名次的情况。比如前3名是并列的名次,排名是正常的1,2,3,4。

这三个函数的区别如下:

sql server窗口函数 sql窗口函数是什么_sql server窗口函数_05


最后,需要强调的一点是:在上述的这三个专用窗口函数中,函数后面的括号不需要任何参数,保持()空着就可以。

3.聚合函数

用途:在窗口中每条记录动态应用聚合函数(sum/avg/max/min/count),可以动态计算在指定的窗口内的各种聚合函数值。

应用场景:截至到当前课程,每个学生的总成绩/平均成绩/最高成绩/最低成绩/课程数是多少?

由于每个窗口函数的条件相同,所以这里将其起个别名w,每个窗口函数只要调用其别名w就好,如下:

SELECT s.sname, c.cname, sc.score,
    SUM(sc.score) OVER w as sumVal,
    AVG(sc.score) OVER w as avgVal,
    MAX(sc.score) OVER w as maxVal,
    MIN(sc.score) OVER w as minVal,
    COUNT(sc.score) OVER w as countgVal
FROM student s INNER JOIN score sc ON s.sid = sc.sid
	       INNER JOIN course c ON sc.cid = c.cid
WINDOW w as (PARTITION BY s.sname ORDER BY sc.score DESC)

sql server窗口函数 sql窗口函数是什么_数据库_06