mysql窗口函數及用法
首先推薦:MYSQL窗口函數 - 知乎 (zhihu.com)這篇文章,寫得非常詳細
含義:窗口函數也叫OLAP函數(Online Anallytical Processing,聯機分析處理),可以對數據進行實時分析處理。
tips: 例子來源於leetcode or 牛客網
分類:
- 專用窗口函數:rank(),dense_rank(),row_number()
- 匯總函數:max(),min(),count(),sum(),avg()
語法:
select 窗口函數 over (partition by 用於分組的列名, order by 用於排序的列名)
一、rank() 函數
說明
- rank()是排序函數,括號中不需要有參數;
- 通過partition by將班級分類,相當於之前用過的group by子句功能,但是group by子句分類匯總會改變原數據的行數,而用窗口函數自救保持原行數;
- 通過order by將成績降序排列,與之前學的order by子句用法一樣,后邊可以升序asc或者降序desc;
注意:窗口函數是對where后者group by子句處理后的結果進行操作,因此按照SQL語句的運行順序,窗口函數一般放在select子句中。
數據表:
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
leetcode 178. 分數排名
在rank()函數,如果有並列情況,會占用下一個名次的位置
SELECT Score ,rank() over(order by Score desc) as 'Rank' from Scores;
//{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 3], [3.65, 4], [3.65, 4], [3.50, 6]]}
在dense_rank()函數,如果有並列情況,則不會占用下一個名次的位置
SELECT Score ,dense_rank() over(order by Score desc) as 'Rank' from Scores;
//{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 2], [3.65, 3], [3.65, 3], [3.50, 4]]}
在row_number()函數中,會忽略並列的情況
SELECT Score ,row_number() over(order by Score desc) as 'Rank' from Scores;
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 2], [3.65, 3], [3.65, 3], [3.50, 4]]}
二、聚合函數 ( leetcode 184. 部門工資最高的員工)
Employee 表包含所有員工信息,每個員工有其對應的 Id, salary 和 department Id。
+----+-------+--------+--------------+
| 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 |
+----+----------+
作用:聚合函數作為窗口函數,是起到"累加/累計"的效果,比如,就是截止到本行,最大值?最小值是多少
與專用窗口函數的區別:括號中需要有指定列,不能為空
select Department,Employee,Salary from (select d.Name Department,e.Name Employee,e.Salary, Max(Salary) over (PARTITION BY d.Name) as max from Employee e join Department d on e.DepartmentId = d.Id) s where Salary = max
//{"headers": ["Department", "Employee", "Salary"], "values": [["IT", "Jim", 90000], ["IT", "Max", 90000], ["Sales", "Henry", 80000]]}

