开窗函数
当我们需要进行一些比较复杂的子查询时,聚合函数就会非常的麻烦,因此可以使用开窗函数进行分组再运用函数查询。窗口函数既可以显示聚集前的数据,也可以显示聚集后的数据,可以在同一行中返回基础行的列值和聚合后的结果列
常见运用场景: 对班里同学成绩进行排序
常见的窗口函数
开窗函数基本形式
func_name(<parameter>)
OVER(
[PARTITION BY <part_by_condition>]
[ORDER BY <order_by_list> ASC|DESC]
[rows between ?? And ??]
)
具体字段的解释看我的上一篇:SQL开窗函数之基本用法和聚合函数
排序函数
排序函数主要有三种
- row_number(): 顺序排序——1,2,3
- rank(): 并列排序,相同的值为同一序号,跳过重复的序号——1,1,3
- dense_rank(): 并列排序,相同的值为同一序号,不跳过重复序号——1,1,2
e.g. Sales表
- 直接排序
select *,
row_number() over(order by sales desc) as row_num,
rank() over(order by sales desc) as rank_num,
dense_rank() over(order by sales desc) as dense_num
from Sales;
- 分组排序
select *,
row_number() over(partition by month(idate) order by sales desc) as row_num,
rank() over(partition by month(idate) order by sales desc) as rank_num,
dense_rank() over(partition by month(idate) order by sales desc) as dense_num
from Sales;
Employee 表
+--------------+---------+
| 列名 | 类型 |
+--------------+---------+
| id | int |
| name | varchar |
| salary | int |
| departmentId | int |
+--------------+---------+
id是此表的主键列。
departmentId是Department表中ID的外键。
此表的每一行都表示员工的ID、姓名和工资。它还包含他们所在部门的ID。
Department 表
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
id是此表的主键列。
此表的每一行都表示一个部门的ID及其名称。
示例:
输入:
Employee 表:
+----+-------+--------+--------------+
| id | name | salary | departmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+----+-------+--------+--------------+
Department 表:
+----+-------+
| id | name |
+----+-------+
| 1 | IT |
| 2 | Sales |
+----+-------+
输出:
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
| IT | Max | 90000 |
+------------+----------+--------+
解释:Max 和 Jim 在 IT 部门的工资都是最高的,Henry 在销售部的工资最高。
答案
-- 使用窗口函数的方式
with a as(
select name, salary, departmentId, rank() over(partition by departmentId order by salary desc) as cnt from Employee
)
select d.name as Department, a.name as Employee, a.salary as Salary from a
left join Department as d
on a.departmentId = d.id
where a.cnt = 1