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

   在一個月黑風高的夜晚,本身無聊學習的SQL的時候,練習,突發奇想的想實現一個功能查詢,一張成績表有以下字段,班級ID,英語成績,數據成績,語文成績以下圖sql

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

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

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

出現這個錯誤,應該就明白了其實數據庫的查詢順序是先分組的,最後纔將結果進行排序。經過正常邏輯思考,經過班級分組,不就是分了三個組:班級1,班級2,班級3 。咱們能夠經過聚合函數查詢出,每一個組的個數,平均值等。但是你後面跟了英語成績什麼鬼?分組以後意味着,咱們不能查詢單個的記錄了,咱們查詢的單位都是關於組的信息。spa

 

第一種實現 1code

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我的。這樣就能夠找到每一個班的前兩名成績。而後按照降序排列。blog

在這種實現中,也能夠加上其餘篩選條件 好比查詢每一個班級女生中英語成績前兩名的記錄排序

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

 

第二種是實現it

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

  最官方,最好的實現方式io

簡單的說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 進行篩選後,再經過分組,組內再排序,排序後在添加編號,實際上是和正常的執行順序同樣的,只不過位置變了

相關文章
相關標籤/搜索