窗口函数
前言
见这种近几、连续、每类前几、各个前几直接考虑窗口函数,这里说下常用的几个:
窗口函数语法都是一样的:
<窗口函数> OVER (partition by <用于分组的列名> order by <用于排序的列名>)
序号函数:row_number、rank、dense_rank
例如:对100,99,99,85,84
row_number的进行排序结果是:1、 2、 3、 4 、5
rank的排序结果是:1、2、2、4、5
dense_rank的排序结果是:1、2、2、3、4
ROW_NUMBER()函数可以理解为排序号,不考虑并列;
RANK()函数也为排号,考虑并列,并列之后的按照实际序号来;
dense_rank()同样是排号,考虑并列,并列之后按下一个名次来。
1)窗口函数:有三种排序方式
-
rank() over() 1 2 2 4 4 6 (计数排名,跳过相同的几个,eg.没有3没有5)
-
row_number() over() 1 2 3 4 5 6 (赋予唯一排名)
-
dense_rank() over() 1 2 2 3 3 4 (不跳过排名,可以理解为对类别进行计数)
2)求时间差函数
timestampdiff(时间格式,开始时间,结束时间)
题目
例一
找到每类试卷得分的前3名,如果两人最大分数相同,选择最小分数大者,如果还相同,选择uid大者。由示例数据结果输出如下:
tid
|
uid
|
ranking
|
SQL
|
1003
|
1
|
SQL
|
1004
|
2
|
SQL
|
1002
|
3
|
算法
|
1005
|
1
|
算法
|
1006
|
2
|
算法
|
1003
|
3
|
试卷信息表examination_info(exam_id试卷ID, tag试卷类别, difficulty试卷难度, duration考试时长, release_time发布时间)
id
|
exam_id
|
tag
|
difficulty
|
duration
|
release_time
|
试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分)
id
|
uid
|
exam_id
|
start_time
|
submit_time
|
score
|
知识点:where不可以引用select里面as 的变量,如果想用需要重新select
select tag, uid, ranking from( SELECT a.tag, b.uid, ROW_NUMBER() OVER ( PARTITION BY tag ORDER BY max(b.score) DESC, min(b.score) DESC, b.uid DESC ) ranking FROM examination_info a LEFT JOIN exam_record b ON a.exam_id = b.exam_id GROUP BY a.tag, b.uid )t1 where ranking<=3
例二
现有试卷作答记录表exam_record(uid:用户ID, exam_id:试卷ID, start_time:开始作答时间, submit_time:交卷时间,为空的话则代表未完成, score:得分):
id
|
uid
|
exam_id
|
start_time
|
submit_time
|
score
|
1
|
1006
|
9003
|
2021-09-06 10:01:01
|
2021-09-06 10:21:02
|
84
|
2
|
1006
|
9001
|
2021-08-02 12:11:01
|
2021-08-02 12:31:01
|
89
|
3
|
1006
|
9002
|
2021-06-06 10:01:01
|
2021-06-06 10:21:01
|
81
|
4
|
1006
|
9002
|
2021-05-06 10:01:01
|
2021-05-06 10:21:01
|
81
|
5
|
1006
|
9001
|
2021-05-01 12:01:01
|
(NULL)
|
(NULL)
|
6
|
1001
|
9001
|
2021-09-05 10:31:01
|
2021-09-05 10:51:01
|
81
|
7
|
1001
|
9003
|
2021-08-01 09:01:01
|
2021-08-01 09:51:11
|
78
|
8
|
1001
|
9002
|
2021-07-01 09:01:01
|
2021-07-01 09:31:00
|
81
|
9
|
1001
|
9002
|
2021-07-01 12:01:01
|
2021-07-01 12:31:01
|
81
|
10
|
1001
|
9002
|
2021-07-01 12:01:01
|
(NULL)
|
(NULL)
|
找到每个人近三个有试卷作答记录的月份中没有试卷是未完成状态的用户的试卷作答完成数,按试卷完成数和用户ID降序排名。由示例数据结果输出如下:
剔除在3个月中有未完成状态试卷的用户,即作答数=完成数
uid
|
exam_complete_cnt
|
1006
|
3
|
解释:用户1006近三个有作答试卷的月份为202109、202108、202106,作答试卷数为3,全部完成;用户1001近三个有作答试卷的月份为202109、202108、202107,作答试卷数为5,完成试卷数为4,因为有未完成试卷,故过滤掉。
SELECT uid,(①) 'exam_complete_cnt' --题设要求输出 FROM(②) A --FROM()内填充排序函数 WHERE(③) --用于筛选近三个月 GROUP BY uid --对每位用户 HAVING(④) --用于过滤近三个月有未完成试卷的用户 ORDER BY exam_complete_cnt DESC,uid DESC; select uid,count(1) count(1)会查询(去重后)所有uid select uid,count(score) count(score)会查询分数不为空或者0的uid
知识点:
窗口函数里的order by 是不能用别名的
timestampdiff(minute , start_time ,submit_time ) AS time_diff
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现