mysql巧用連表查詢各科成績前三名

下列是各表的詳情,不想本身建表的同窗能夠直接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

left join

如今咱們能夠再進一步處理上面的數據了。這裏咱們再加上 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>=其餘分數 這個條件,因此100分出現次數最多(count爲總人數)
  • 0分,是最低分,幾乎其餘全部分數都不符合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

相關文章
相關標籤/搜索