什么是开窗函数?
开窗函数是一种用于分析数据的强大功能,MySQL从8.0版本开始支持。开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。开窗函数有以下几种类型:
– 聚合开窗函数:sum,avg,count,max,min等,用于计算基于组的某种聚合值。
– 排名开窗函数:row_number,dense_rank,rank等,用于对数据进行排序和排名。
– 值分布开窗函数:first_value,last_value,nth_value等,用于获取数据中的特定值。
– 导航开窗函数:lead,lag等,用于获取数据中的前后值。
1.sum()
sum开窗函数是一种聚合开窗函数,用于计算基于组的某种聚合值,它和聚合函数的不同之处是:sum开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。sum开窗函数的语法如下:
sum(列名) over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的列名进行求和,并返回每一行的累计和。例如,假设有一个成绩表score,有三个字段:学生s_id,课程c_id,成绩s_score。如果想要计算每个学生在每门课程上的累计成绩,可以使用以下语句:
select s_id, c_id, s_score, sum(s_score) over (partition by s_id order by c_id) as total_score from score;
这样就可以得到类似如下的结果:
s_id |
c_id |
s_score |
total_score |
1 |
1 |
80 |
80 |
1 |
2 |
90 |
170 |
1 |
3 |
85 |
255 |
2 |
1 |
75 |
75 |
2 |
2 |
80 |
155 |
… … … … |
2.avg()
avg开窗函数是一种聚合开窗函数,用于计算基于组的某种聚合值,它和聚合函数的不同之处是:avg开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。avg开窗函数的语法如下:
avg(列名) over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的列名进行求平均值,并返回每一行的累计平均值。例如,假设有一个成绩表score,有三个字段:学生s_id,课程c_id,成绩s_score。如果想要计算每个学生在每门课程上的累计平均成绩,可以使用以下语句:
select s_id, c_id, s_score, avg(s_score) over (partition by s_id order by c_id) as avg_score from score;
这样就可以得到类似如下的结果:
s_id |
c_id |
s_score |
avg_score |
1 |
1 |
80 |
80 |
1 |
2 |
90 |
85 |
1 |
3 |
85 |
85 |
2 |
1 |
75 |
75 |
… … … … |
3.count()
count开窗函数是一种聚合开窗函数,用于计算基于组的某种聚合值,它和聚合函数的不同之处是:count开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。count开窗函数的语法如下:
count(列名) over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的列名进行计数,并返回每一行的累计计数。例如,假设有一个成绩表score,有三个字段:学生s_id,课程c_id,成绩s_score。如果想要计算每个学生在每门课程上的累计参与人数,可以使用以下语句:
select s_id, c_id, s_score, count(s_score) over (partition by c_id order by s_score) as count_score from score;
这样就可以得到类似如下的结果:
s_id |
c_id |
s_score |
count_score |
1 |
1 |
80 |
2 |
2 |
1 |
75 |
1 |
3 |
1 |
85 |
3 |
… … … … |
4.max()
max开窗函数是一种聚合开窗函数,用于计算基于组的某种聚合值,它和聚合函数的不同之处是:max开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。max开窗函数的语法如下:
max(列名) over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的列名进行求最大值,并返回每一行的累计最大值。例如,假设有一个成绩表score,有三个字段:学生s_id,课程c_id,成绩s_score。如果想要计算每个学生在每门课程上的累计最高成绩,可以使用以下语句:
select s_id, c_id, s_score, max(s_score) over (partition by c_id order by s_score) as max_score from score;
这样就可以得到类似如下的结果:
s_id |
c_id |
s_score |
max_score |
1 |
1 |
80 |
85 |
2 |
1 |
75 |
85 |
3 |
1 |
85 |
85 |
… … … … |
5.min()
min开窗函数是一种聚合开窗函数,用于计算基于组的某种聚合值,它和聚合函数的不同之处是:min开窗函数可以在分组之后的返回多行结果,而聚合函数对于每个组只返回一行。min开窗函数的语法如下:
min(列名) over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的列名进行求最小值,并返回每一行的累计最小值。例如,假设有一个成绩表score,有三个字段:学生s_id,课程c_id,成绩s_score。如果想要计算每个学生在每门课程上的累计最低成绩,可以使用以下语句:
select s_id, c_id, s_score, min(s_score) over (partition by c_id order by s_score) as min_score from score;
这样就可以得到类似如下的结果:
s_id |
c_id |
s_score |
min_score |
1 |
1 |
80 |
75 |
2 |
1 |
75 |
75 |
3 |
1 |
85 |
75 |
… … … … |
6.row_number()
row_number开窗函数是一种排序开窗函数,用于为每一行分配一个序号,从1开始递增。row_number开窗函数的语法如下:
row_number() over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的行进行编号。例如,假设有一个员工表employee,有三个字段:部门d_id,姓名e_name,薪水e_salary。如果想要计算每个部门的员工薪水排名,可以使用以下语句:
select d_id, e_name, e_salary, row_number() over (partition by d_id order by e_salary desc) as rank from employee;
这样就可以得到类似如下的结果:
d_id |
e_name |
e_salary |
rank |
1 |
Alice |
5000 |
1 |
1 |
Bob |
4000 |
2 |
1 |
Carol |
3000 |
3 |
… … … … |
7.dense_rank()
dense_rank开窗函数是一种排序开窗函数,用于为每一行分配一个排名,而排名值没有间隙。dense_rank开窗函数的语法如下:
dense_rank() over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的行进行排名。如果分区有两个或更多具有相同排名值的行,则为这些行中的每一行分配相同的排名。与rank开窗函数不同,dense_rank开窗函数始终返回连续的排名值。例如,假设有一个商品表product,有三个字段:类别p_type,名称p_name,价格p_price。如果想要计算每个类别的商品价格排名,可以使用以下语句:
select p_type, p_name, p_price, dense_rank() over (partition by p_type order by p_price desc) as rank from product;
这样就可以得到类似如下的结果:
p_type |
p_name |
p_price |
rank |
A |
X |
100 |
1 |
A |
Y |
80 |
2 |
A |
Z |
80 |
2 |
… … … … |
8.rank()
rank开窗函数是一种排序开窗函数,用于为每一行分配一个排名,而排名值有间隙。rank开窗函数的语法如下:
rank() over (partition by 分组列 order by 排序列)
这表示对分组列进行分组,然后按照排序列进行排序,最后对每个分组内的行进行排名。如果分区有两个或更多具有相同排名值的行,则为这些行中的每一行分配相同的排名。与dense_rank开窗函数不同,rank开窗函数会跳过重复的排名值。例如,假设有一个商品表product,有三个字段:类别p_type,名称p_name,价格p_price。如果想要计算每个类别的商品价格排名,可以使用以下语句:
select p_type, p_name, p_price, rank() over (partition by p_type order by p_price desc) as rank from product;
这样就可以得到类似如下的结果:
p_type |
p_name |
p_price |
rank |
A |
X |
100 |
1 |
A |
Y |
80 |
2 |
A |
Z |
80 |
2 |
… … … … |
9.first_value()
first_value开窗函数是一种返回窗口框架,分区或结果集的第一行的值的函数。first_value开窗函数的语法如下:
first_value(表达式) over ([partition by 分组列] [order by 排序列] [frame_clause])
这表示对分组列进行分组,然后按照排序列进行排序,最后返回每个分组内的第一行的表达式的值。如果没有指定frame_clause,则默认为range between unbounded preceding and current row,即从分区开始到当前行。例如,假设有一个员工表employee,有四个字段:部门dept_no,姓名emp_name,工资salary,小时hourly_rate。如果想要计算每个部门的最高工资和最高小时率,并显示每个员工与之的差距,可以使用以下语句:
select dept_no, emp_name, salary, hourly_rate, first_value(salary) over (partition by dept_no order by salary desc) as max_salary, first_value(hourly_rate) over (partition by dept_no order by hourly_rate desc) as max_hourly_rate, first_value(salary) over (partition by dept_no order by salary desc) - salary as salary_gap, first_value(hourly_rate) over (partition by dept_no order by hourly_rate desc) - hourly_rate as hourly_rate_gap from employee;
这样就可以得到类似如下的结果:
dept_no |
emp_name |
salary |
hourly_rate |
max_salary |
max_hourly_rate |
salary_gap |
hourly_rate_gap |
1 |
Alice |
5000 |
50 |
5000 |
50 |
0 |
0 |
1 |
Bob |
4000 |
40 |
5000 |
50 |
1000 |
10 |
… … … … … … … … |
10.last_value()
last_value开窗函数是一种返回窗口框架,分区或结果集的最后一行的值的函数。last_value开窗函数的语法如下:
last_value(表达式) over ([partition by 分组列] [order by 排序列] [frame_clause])
这表示对分组列进行分组,然后按照排序列进行排序,最后返回每个分组内的最后一行的表达式的值。如果没有指定frame_clause,则默认为range between unbounded preceding and current row,即从分区开始到当前行。例如,假设有一个学生成绩表student_scores,有四个字段:学号studentId,数学成绩math,系别departmentId,班级classId。如果想要计算每个班级的数学成绩的最大值和最小值,并显示每个学生与之的差距,可以使用以下语句:
select studentId, math, departmentId, classId, last_value(math) over (partition by classId order by math) as max_math, first_value(math) over (partition by classId order by math) as min_math, last_value(math) over (partition by classId order by math) - math as math_gap from student_scores where departmentId = 'department1';
这样就可以得到类似如下的结果:
studentId |
math |
departmentId |
classId |
max_math |
min_math |
math_gap |
111 |
69 |
department1 |
class1 |
94 |
69 |
25 |
113 |
74 |
department1 |
class1 |
94 |
69 |
20 |
… … … … … … … |
11.nth_value()
nth_value开窗函数是一种返回窗口框架,分区或结果集中第N行的值的函数。nth_value开窗函数的语法如下:
nth_value(表达式, N) over ([partition by 分组列] [order by 排序列] [frame_clause])
这表示对分组列进行分组,然后按照排序列进行排序,最后返回每个分组内的第N行的表达式的值。如果没有指定frame_clause,则默认为range between unbounded preceding and current row,即从分区开始到当前行。例如,假设有一个学生成绩表student_scores,有四个字段:学号studentId,数学成绩math,系别departmentId,班级classId。如果想要计算每个班级的数学成绩的中位数和平均数,并显示每个学生与之的差距,可以使用以下语句:
select studentId, math, departmentId, classId, nth_value(math, count(*) over (partition by classId) / 2) over (partition by classId order by math) as median_math, avg(math) over (partition by classId) as avg_math, nth_value(math, count(*) over (partition by classId) / 2) over (partition by classId order by math) - math as median_gap, avg(math) over (partition by classId) - math as avg_gap from student_scores where departmentId = 'department1';
这样就可以得到类似如下的结果:
studentId |
math |
departmentId |
classId |
median_math |
avg_math |
median_gap |
avg_gap |
111 |
69 |
department1 |
class1 |
82 |
80.5 |
13 |
11.5 |
113 |
74 |
department1 |
class1 |
82 |
80.5 |
8 |
6.5 |
… … … … … … … … |
12.lead()
lead开窗函数是一种允许你向前看多行并从当前行访问行的数据的函数。lead开窗函数的语法如下:
lead(表达式, N) over ([partition by 分组列] [order by 排序列])
这表示对分组列进行分组,然后按照排序列进行排序,最后返回每个分组内的当前行之后的第N行的表达式的值。如果没有指定N,则默认为1,即返回下一行的值。例如,假设有一个员工工资表employee_salaries,有三个字段:员工编号empId,姓名name,工资salary。如果想要计算每个员工与其下一个员工(按照工资降序排列)的工资差距,可以使用以下语句:
select empId, name, salary, lead(salary) over (order by salary desc) as next_salary, salary - lead(salary) over (order by salary desc) as salary_gap from employee_salaries;
这样就可以得到类似如下的结果:
empId |
name |
salary |
next_salary |
salary_gap |
101 |
Tom |
10000 |
8000 |
2000 |
102 |
Bob |
8000 |
7000 |
1000 |
… … … … … |
13.lag()
lag开窗函数是一种允许你向后看多行并从当前行访问行的数据的函数。lag开窗函数的语法如下:
lag(表达式, N) over ([partition by 分组列] [order by 排序列])
这表示对分组列进行分组,然后按照排序列进行排序,最后返回每个分组内的当前行之前的第N行的表达式的值。如果没有指定N,则默认为1,即返回上一行的值。例如,假设有一个商品销售表product_sales,有四个字段:商品编号productId,商品名称productName,销售日期saleDate,销售数量saleQuantity。如果想要计算每个商品每天与前一天(按照日期升序排列)的销售数量差异,可以使用以下语句:
select productId, productName, saleDate, saleQuantity, lag(saleQuantity) over (partition by productId order by saleDate) as prev_quantity, saleQuantity - lag(saleQuantity) over (partition by productId order by saleDate) as quantity_diff from product_sales;
这样就可以得到类似如下的结果:
productId |
productName |
saleDate |
saleQuantity |
prev_quantity |
quantity_diff |
1001 |
Apple |
2023-01-01 |
50 |
NULL |
NULL |
1001 |
Apple |
2023-01-02 |
60 |
50 |
10 |
… … … … … … |
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/16031.html