在一個月黑風高的夜晚,本身無聊學習的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() 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 進行篩選後,再經過分組,組內再排序,排序後在添加編號,實際上是和正常的執行順序同樣的,只不過位置變了