注意:开窗函数在mysql8.0后才有
函数名(列) over(选项【选项可以为 partition by 列 order by 列】)
over(partition by xxx) 按照xxx所有行进行分组
over(partition by xxx order by aaa) 按照xxx分组,按照aaa排序
计算每个学生的及格数
-- 使用聚合函数
select student_id,count(sid) from score where num>=60 group by student_id;
-- 使用开窗函数
select sid,student_id,count(sid) over(partition by student_id order by student_id) 及格数
from score where num>=60;
开窗函数不会修改源数据表的结构,会在表的最后一列添加想要的结果,如果分组存在多行数据,则重复显示
-- 看代码区分关系
select s.sid,s1.sname,s1.gender,c.cname,s.num,
row_number() over(partition by c.cname order by num desc) as row_number排名,
rank() over(partition by c.cname order by num desc) as rank排名,
dense_rank() over(partition by c.cname order by num desc) as dense_rank排名,
ntile(6) over(partition by c.cname order by num desc) as ntile排名
from score as s
join student s1 on s.student_id=s1.sid
left join course c on s.course_id=c.cid;
案例:
-- 查询各科成绩前三名的学生成绩信息
select * from(
select s.sid,s1.sname,s1.gender,c.cname,s.num,
dense_rank() over(partition by c.cname order by num desc) as dense_rank排名
from score as s
join student s1 on s.student_id=s1.sid
left join course c on s.course_id=c.cid) as e
where dense_rank排名<=3;
lag(col,n)
统计窗口内向上第n行值
lead(col,n)
统计窗口内往下第n行值
这两种函数可以用于同列中相邻行的数据相减操作
案例
-- 对于下面的数据,对于同一用户(uid)如果在2分钟之内重新登录,则判断为作弊,统计哪些用户有作弊行为,并计算作弊次数
-- 去时间差
SELECT *,
format(相差秒数 / 60, 3) 相差分钟数
FROM
( SELECT id,
uid,
login_time,
-- 加一列时间
lead (login_time, 1) over ( PARTITION BY uid ORDER BY login_time ) lead_time,
-- 求2列时间的差值
timestampdiff(
SECOND,
login_time,
( lead (login_time, 1) over ( PARTITION BY uid ORDER BY login_time ))
) 相差秒数
FROM lag_table ) as e;
-- 求作弊次数
SELECT uid,count(1) 作弊次数
FROM
( SELECT id,
uid,
login_time,
-- 加一列时间
lead (login_time, 1) over ( PARTITION BY uid ORDER BY login_time ) lead_time,
-- 求2列时间的差值
timestampdiff(
SECOND,
login_time,
( lead (login_time, 1) over ( PARTITION BY uid ORDER BY login_time ))
) 相差秒数
FROM lag_table ) as e
where format(相差秒数 / 60, 3)<=2 group by uid;
first_value(column)
取分组内排序后,截止当前行,第一个值
-- 取科目成绩最大值
-- 根据降序,第一个值是最大值
select s.sid,s1.sname,s1.gender,c.cname,s.num,
first_value(num) over(partition by c.cname order by num desc) as firstvalue
from score s join student s1 on s.student_id=s1.sid
left join course c on s.course_id=c.cid;
last_value(column)
修改范围:
在order by 后面加上rows between unbounded preceding and unbounded following
即:order by rows between unbounded preceding and unbounded following
就变为:当前分组数据与数据进行比较,取最后一个值
unbounded 无限制的
preceding 分区的当前记录向前的偏移量
current 当前
following 分区的当前记录向后偏移量
-- 取科目成绩最小值
-- 根据降序,最后一个值是最小值,要修改范围
select s.sid,s1.sname,s1.gender,c.cname,s.num,
last_value(num) over(partition by c.cname order by num desc rows between unbounded preceding and unbounded following) as lastvalue
from score s join student s1 on s.student_id=s1.sid
left join course c on s.course_id=c.cid;