mysql 取分組數據的前幾名(1)

目前有需求需要取分組數據的前幾名,有如下的解決方案來實現

具體數據庫如下

SQL寫法:

SELECT
	* 
FROM
	student_grade AS a 
WHERE
	( SELECT coun ( * ) FROM student_grade AS b WHERE b.subid = a.subid AND b.grade >= a.grade ) <= 2 
ORDER BY
	a.subid,
	a.grade DESC

結果

 

理解:

    核心思路:要算出某人成績在第幾名,可以轉換成:算出他一共比多少人成績高。比如,第一名的人,就沒其它人成績比他更好。第三名的人,就有兩個人成績比他好。

    where語句可以理解爲,把表中的每一行記錄,都去與給定的where條件作對比,滿足的再查出來。也就是有個遍歷的過程。

模擬下SQL執行的過程就是,先取出外層a表的第一條記錄

執行where中的子查詢:

select count(1) from student_grade b where b.subId=1 and b.grade>=97

加粗的數據,即從外層a表取出來的。意思是課程1中,有多少個學生的成績是大於等於97的?97已是最高分了,只有一個。因此滿足外層的條件,小於等於2.

接下來取外層表第二條記錄

where子句變成了:

select count(1) from student_grade b where b.subId=1 and b.grade>=93

意思是課程1中,有多少個學生的成績是大於等於93的?結果是2,因爲97和93分都大於等於93分。因此滿足外層的條件,小於等於2.這樣就取出了每門課的前兩名。

接下來取外層表第三條記錄:

where子句變成了:

select count(1) from student_grade b where b.subId=1 and b.grade>=92

意思是課程1中,有多少個學生的成績是大於等於92的?結果是3,因爲97、93、92分都大於等於92分。因此不滿足外層的條件,小於等於2.

以此類推...

 

擴展一下:

    取每組第一名的記錄,只需要把下圖紅框處改爲<=1

    取每組成績最低的,只需把下圖黑框處改爲b.grade<=a.grade

 

此外需要注意的是,該方法在有相同的多個數據時,會導致相同結果全部被選中,此時可以考慮採用另外的方法:

SELECT
	s2.stuid,
	s2.subid,
	s2.grade 
FROM
	(
	SELECT
	IF
		( s1.subid = @subid, @rank := @rank + 1, @rank := 1 ) AS rank,
		@subid := subid AS tmp_subid,
		s1.stuid,
		s1.subid,
		s1.grade 
	FROM
		( SELECT stuid, subid, grade FROM student_grade ORDER BY subid, grade DESC ) s1,
		( SELECT @subid := NULL, @rank := 1 ) tmp 
	) s2 
WHERE
	s2.rank <= 2

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章