1. 程式人生 > >SQL實現group by 分組後組內排序

SQL實現group by 分組後組內排序

   在一個月黑風高的夜晚,自己無聊學習的SQL的時候,練習,突發奇想的想實現一個功能查詢,一張成績表有如下欄位,班級ID,英語成績,資料成績,語文成績如下圖

實現 查詢出 每個班級英語成績最高的前兩名的記錄。

看起來不難的業務,做起來才知道還挺麻煩的,說白了其實就是實現分組後的組內排序,一般不思考的話我們會寫出這樣的語句:

select top 2 English,Classid from CJ group by Classid order by English desc

出現這個錯誤,應該就明白了其實資料庫的查詢順序是先分組的,最後才將結果進行排序。通過正常邏輯思考,通過班級分組,不就是分了三個組:班級1,班級2,班級3 。我們可以通過聚合函式查詢出,每個組的個數,平均值等。可是你後面跟了英語成績什麼鬼?分組之後意味著,我們不能查詢單個的記錄了,我們查詢的單位都是關於組的資訊。

 

第一種實現 1

SELECT * FROM CJ m
 where(
 select COUNT(*) from CJ n
     where m.Classid = n.Classid and n.English > m.English)<2
	 order by Classid, English desc

  也是當網上查的,可以這樣理解,要找出前兩名的成績,只要符合比你成績高的不超過2個人就行了。其實是一個表的自連線,where條件就是一條一條記錄對比,首先在m表中拿一條記錄,是否符合 在同一班級中 比你成績高的不超過2個人。這樣就可以找到每個班的前兩名成績。然後按照降序排列。

在這種實現中,也可以加上其他篩選條件 比如查詢每個班級女生中英語成績前兩名的記錄

SELECT * FROM (select * from CJ where Gender='') m
 where(
 select COUNT(*) from (select * from CJ where Gender='') n
     where m.Classid = n.Classid and n.English > m.English)<2
     order by Classid, English desc


SELECT * FROM CJ m
 where(
 
select COUNT(*) from CJ n where m.Classid = n.Classid and n.English > m.English and n.Gender='')<2 --指的是內表 and Gender='' --指的是外表 order by Classid, English desc

 

第二種是實現

select a.Classid,a.English from
(select Classid,English,row_number() over(partition by Classid order by English desc) as n
from CJ) a
where n<=2

  最官方,最好的實現方式

簡單的說row_number()從1開始,為每一條分組記錄返回一個數字

row_number() OVER (PARTITION BY COL1 ORDER BY COL2) 表示根據COL1分組,在分組內部根據 COL2排序,而此函式計算的值就表示每組內部排序後的順序編號(組內連續的唯一的)

同樣的加上條件

select a.Classid,a.English,n,test from
(select Classid,English,row_number() over(partition by Classid order by English desc) as n,123 test
from CJ where CJ.Gender='') a
where n<=2

可以看出先執行的是where 進行篩選後,再通過分組,組內再排序,排序後在新增編號,其實是和正常的執行順序一樣的,只不過位置變了