在沒學習開窗函數以前,咱們都知道,用了分組以後,查詢字段就只能是分組字段和聚合的字段,這帶來了極大的不方便,有時咱們查詢時須要分組,又須要查詢不分組的字段,每次都要又到子查詢,這樣顯得sql語句複雜難懂,給維護代碼的人帶來很大的痛苦,然而開窗函數出現了,曙光也來臨了。若是要想更具體瞭解開窗函數,請看書《程序員的SQL金典》,開窗函數在mysql不能使用。mysql
開窗函數與聚合函數同樣,都是對行的集合組進行聚合計算。它用於爲行定義一個窗口(這裏的窗口是指運算將要操做的行的集合),它對一組值進行操做,不須要使用group by語句對數據進行分組,可以在同一行中同時返回基礎行的列和聚合列。定義看不懂沒關係,會用就行。程序員
舉個簡單例子 查詢每一個工資小於5000的員工信息(姓名,城市 年齡 薪水),而且顯示小於5000的員工個數,嘗試使用下面語句:sql
SELECT FName, FCITY, FAGE, FSalary, COUNT(FName) FROM T_Person WHERE FSALARY<5000
消息 8120,級別 16,狀態 1,第 1 行 選擇列表中的列 'T_Person.FName' 無效,由於該列沒有包含在聚合函數或 GROUP BY 子句中。
可使用子查詢實現,語句:函數
SELECT FName, FCITY, FAGE, FSalary, ( SELECT COUNT(FName) FROM T_Person WHERE FSALARY<5000 ) PersonNum FROM T_Person WHERE FSALARY<5000
結果:學習
使用開窗函數實現,查詢結果如出一轍,就不粘貼了:fetch
SELECT FName, FCITY, FAGE, FSalary, COUNT(FName) OVER() as PersonNum FROM T_Person WHERE FSALARY<5000
1.開窗函數格式:函數名(列) OVER(選項)spa
2.聚合開窗函數格式:聚合函數(列) OVER(PARTITION BY 字段)3d
over關鍵字把聚合函數當成聚合開窗函數而不是聚合函數,SQL標準容許將全部的聚合函數用作聚合開窗函數。OVER關鍵字後的括號中還常常添加選項用以改變進行聚合運算的窗口範圍。若是OVER關鍵字後的括號爲空,則開窗函數會對結果集合的全部行進行聚合運算。code
PARTITION BY來定義行的分區來進行聚合運算,與group by 不一樣,partition by 字句建立的分區是獨立於結果集的,建立的分區只是用於進行聚合運算,並且不一樣的開窗函數所建立的分區不互相影響,例如:查詢全部人員的信息,並查詢所屬城市的人員數以及同年齡的人員數:blog
SELECT FName,FCITY, FAGE, FSalary, COUNT(FName) OVER(PARTITION BY FCITY) CityNum, COUNT(FName) OVER(PARTITION BY FAGE) AgeNum FROM T_Person ORDER by FCITY
查詢全部人員的信息,並查詢所屬城市的人員數,每一個城市的人按照年齡排序語句:
SELECT FName,FCITY, FAGE, FSalary, COUNT(FName) OVER(PARTITION BY FCITY ORDER BY FAGE) CityNum FROM T_Person
3.排序開窗函數格式:排序函數() OVER(ORDER BY 字段)
(1)主要函數有ROW_NUMBER()、RANK()、DENSE_RANK()、NTILE()
ROW_NUMBER() 加行號,通常能夠用於分頁查詢(如今被offset fetch取代 ),對於沒有主鍵列的表加行號做用很明顯,刪除重複數據等。
按照薪水高低給全部人員排序,一樣薪水的排名不同,能夠用row_number(),
with a as ( SELECT FName, FSalary, FCity, FAge, ROW_NUMBER() over(ORDER BY FSalary) as RowNum FROM T_Person ) SELECT * FROM a
使用rank()將每一個城市的薪水排行,值同樣的同一個排名,出現兩個第一名的時候,排在兩個第一名後的排名將是第三名
SELECT FName, FSalary, FCity, FAge, RANK() over(PARTITION BY FCITY ORDER BY FSalary) as RankNum FROM T_Person
使用dense_rank()將每一個城市的薪水排行,值同樣的同一個排名,出現兩個第一名的時候,排在兩個第一名後的排名將是第三名