1. 程式人生 > >SQL之開窗函式詳解--可代替聚合函式使用

SQL之開窗函式詳解--可代替聚合函式使用

       在沒學習開窗函式之前,我們都知道,用了分組之後,查詢欄位就只能是分組欄位和聚合的欄位,這帶來了極大的不方便,有時我們查詢時需要分組,又需要查詢不分組的欄位,每次都要又到子查詢,這樣顯得sql語句複雜難懂,給維護程式碼的人帶來很大的痛苦,然而開窗函數出現了,曙光也來臨了。如果要想更具體瞭解開窗函式,請看書《程式設計師的SQL金典》,開窗函式在mysql不能使用。

       開窗函式與聚合函式一樣,都是對行的集合組進行聚合計算。它用於為行定義一個視窗(這裡的視窗是指運算將要操作的行的集合),它對一組值進行操作,不需要使用group by語句對資料進行分組,能夠在同一行中同時返回基礎行的列和聚合列。定義看不懂不要緊,會用就行。

       舉個簡單例子 查詢每個工資小於5000的員工資訊(姓名,城市 年齡 薪水),並且顯示小於5000的員工個數,嘗試使用下面語句:

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

       結果:

     使用開窗函式實現,查詢結果一模一樣,就不貼上了:

SELECT FName, FCITY, FAGE, FSalary, COUNT(FName) OVER() as PersonNum FROM T_Person 
WHERE FSALARY<5000

1.開窗函式格式:函式名(列) OVER(選項)

2.聚合開窗函式格式:聚合函式(列) OVER(PARTITION BY 欄位)

      over關鍵字把聚合函式當成聚合開窗函式而不是聚合函式,SQL標準允許將所有的聚合函式用做聚合開窗函式。OVER關鍵字後的括號中還經常新增選項用以改變進行聚合運算的視窗範圍。如果OVER關鍵字後的括號為空,則開窗函式會對結果集合的所有行進行聚合運算。

      PARTITION BY來定義行的分割槽來進行聚合運算,與group by 不同,partition by 字句建立的分割槽是獨立於結果集的,建立的分割槽只是用於進行聚合運算,而且不同的開窗函式所建立的分割槽不互相影響,例如:查詢所有人員的資訊,並查詢所屬城市的人員數以及同年齡的人員數:

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()將每個城市的薪水排行,值一樣的同一個排名,出現兩個第一名的時候,排在兩個第一名後的排名將是第三名

&n