下列是各表的詳情,不想本身建表的同窗能夠直接copy code,數據隨意。
建立表成績詳情表: sql
CREATE TABLE score ( id int(10) NOT NULL AUTO_INCREMENT, subject_id int(10) DEFAULT NULL, student_id int(10) DEFAULT NULL, score float DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
建立學生表: spa
CREATE TABLE student ( id int(10) NOT NULL AUTO_INCREMENT, name varchar(10) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
建立科目表: code
CREATE TABLE subject ( id int(10) NOT NULL AUTO_INCREMENT, name varchar(10) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
查詢語句:blog
select a.id,a.subject_id,a.student_id,a.score from score as a left join score as b on a.subject_id=b.subject_id and a.score>=b.score group by a.subject_id,a.student_id,a.score having count(a.subject_id)>=4 order by a.subject_id,a.score desc;
分析:先將查詢語句分別拆開來一步一步分析 排序
select a.id,a.subject_id,a.student_id,a.score,b.id,b.subject_id,b.student_id,b.score from score as a left join score as b on a.subject_id=b.subject_id;
#這裏把全部的列都列出來了便於對比
這裏把表score的每一條同subject_id的數據都鏈接起來,造成笛卡爾積,如圖所示:共18*6=108條數據 get
如今咱們能夠再進一步處理上面的數據了。這裏咱們再加上 a.score>=b.score 這個條件篩選再進行一次篩選。 class
select a.id,a.subject_id,a.student_id,a.score,b.id,b.subject_id,b.student_id,b.score from score as a left join score as b on a.subject_id=b.subject_id and a.score>=b.score;
a.score>=b.score 這裏是在同一門課程中,將每個分數與其餘分數(包括本身)進行一一對比,只留下大於本身,或者等於本身的分數。select
若是選擇對比的行中的a.score是最高分,那麼在後面利用group by a.subject_id,a.student_id,a.score分組的時候,此時計算得出的count(a.subject_id)就是最多的(count爲總人數),由於其它的分數最多也只是和它同樣多,其它的都比它低;同理,若是a.score是最低分,那麼count(a.subject_id)是最少的(count最少爲1,只有它本身,其他分數都比它高;最多爲總人數,這種狀況是其它人的分數都和最低分同樣多...),其它的分數最差也和它同樣多,其它的都比它要高。例如:float
100>=其餘分數
這個條件,因此100分出現次數最多(count爲總人數)0>=其餘分數
這個條件,因此0分出現的次數應該是最少的(count最少爲1;最多爲總人數,此時其餘的分數也都是最低分,即你們分數同樣低)
有同窗可能會問爲何不用a.score > b.score來篩選。若是用a.score > b.score來進行篩選的話,若是數據中某個科目出現大量的並列第一名的話那麼第一名就會被過濾掉,以致於得不到結果。如圖: im
接下來就是分組:group by a.subject_id,a.student_id,a.score #按subject_id,student_id,score來進行分組
(這裏使用group by a.subject_id,a.student_id,a.score和使用group by a.subject_id,a.student_id同樣的,由於兩表左鏈接以後,不可能出現相同的a.subject_id,a.student_id有多條不一樣的a.score的記錄;由於同一個同窗a.student_id,同一個科目a.subject_id,只能有一個分數a.score,一個同窗不可能一個科目有多個不一樣的分數);
select a.id,a.subject_id,a.student_id,a.score,b.id,b.subject_id,b.student_id b.score,count(a.subject_id) from score as a left join score as b on a.subject_id=b.subject_id and a.score>=b.score group by a.subject_id,a.student_id,a.score;
添加count(a.subject_id)來進行對比易於理解
分組後再進行條件查詢:having count(a.subject_id)>=4;
下面來討論下>=4是什麼含義:正常來講,若是每門課程的各個同窗的分數都不同,那麼同一門課程中從最高分到最低分的count(a.subject_id) 分別爲:6,5,4,3,2,1;取count>=4就是取6,5,4即取count最多的三個,因此取出的數據就是排名前三(count從高到低,取前三,那麼就是前三甲的記錄):
接下來就是排序:order by a.subject_id,a.score desc。
下面有篇文章,講解的很詳細:https://www.jianshu.com/p/fff5d1f71c0f