- 表結構如下圖
+-----+------------+-----------+-------+
| sid | student_id | course_id | score |
+-----+------------+-----------+-------+
| 1 | 1 | 1 | 60 |
| 2 | 1 | 2 | 59 |
| 3 | 2 | 2 | 99 |
| 5 | 3 | 1 | 77 |
| 6 | 3 | 2 | 78 |
| 7 | 4 | 1 | 59 |
| 8 | 5 | 2 | 20 |
| 9 | 6 | 1 | 99 |
| 10 | 6 | 2 | 100 |
| 11 | 7 | 1 | 0 |
| 12 | 7 | 2 | 1 |
| 13 | 8 | 1 | 100 |
| 14 | 9 | 2 | 100 |
| 15 | 9 | 3 | 50 |
| 16 | 9 | 1 | 60 |
- 排名方法如下
select s1.course_id,s1.score,count(distinct s2.score)
from score as s1
inner join score as s2
on s1.course_id = s2.course_id and s1.score >= s2.score
group by s1.course_id,s1.score
;
-
首先將分數表score自連接
按照第一個條件
s1.course_id = s2.course_id
把s1表的課程id和s2表的課程id對應起來,但是會產生多餘的數據(會將不同sid,student_id,score,但是course_id相同的數據都連接一次),所以需要第二個條件進一步篩選我們的理想數據-
按照第二個條件
s1.score >= s2.score
將分數進行對比,然後進行連接,連接後的結果就是在同一門課程中,將每一個分數與其他分數(包括自己)進行一一對比,只留下大於自己,或者等於自己的分數.-
到了這裏,經過連接後的表中的內容理想的情況會是,
- 100分是最高的,所以幾乎其他所有分數都符合
100>=其他分數
這個條件,所以100分出現次數最多, - 又比如0分,是最低分,幾乎其他所有分數都不符合
0>=其他分數
這個條件,所以0分出現的次數應該是最少的, - 至此,我們只要按
group by s1.course_id,s1.score
分組,然後count(s2.score)
出現次數從多到少排序可以找到每門課程從高到低的分數了.
這裏再說一下爲什麼是
count(s2.score)
,而不是count(s1.score)
,因爲我們是按s1.score分組的,如果取count(s1.score)
,得到的結果都會是1 - 100分是最高的,所以幾乎其他所有分數都符合
-
但是,理想是豐滿的,現實卻很骨感,由於相同分數情況的出現,單純的去統計按照
s1.course_id = s2.course_id and s1.score >= s2.score
條件連接表的
s2.score
出現次數並不能準確的排列出最高分和最低分,舉個例子說明一下:- 比如不同的學生,同一門課程,都是60分,而且這種情況很多,這就會導致我們上面所說的查詢方法錯誤,有可能60出現的次數甚至超過100分,從而導致排序後出現的最高分成了60分.有多少個學生都是同一門課程相同的分數,我們上面所統計的個數就會多幾次.
+-----------+-------+-----------------+ | course_id | score | count(s2.score) | +-----------+-------+-----------------+ | 1 | 0 | 1 | | 1 | 59 | 2 | | 1 | 60 | 8 | | 1 | 77 | 5 | | 1 | 99 | 6 | | 1 | 100 | 16 | | 2 | 1 | 1 | | 2 | 20 | 2 | | 2 | 59 | 3 | | 2 | 78 | 4 | | 2 | 99 | 5 | | 2 | 100 | 14 | # 如上,課目1的60分出現次數超過了77分出現的次數,但是明顯60是應該排在77之後的.
-
所以select語句只能寫成這樣
select s1.course_id,s1.score,count(distinct s2.score)
要去重!!!
首先通過
group by s1.course_id,s1.score
分組,將所有相同課程,相同分數的數據分到了一個組裏面,通過count(distinct s2.score)
中的distinct把重複出現的相同課程,相同分數的數據去掉!!!得到我們想要的數據
+-----------+-------+--------------------------+ | course_id | score | count(distinct s2.score) | +-----------+-------+--------------------------+ | 1 | 0 | 1 | | 1 | 59 | 2 | | 1 | 60 | 3 | | 1 | 77 | 4 | | 1 | 99 | 5 | | 1 | 100 | 6 | | 2 | 1 | 1 | | 2 | 20 | 2 | | 2 | 59 | 3 | | 2 | 78 | 4 | | 2 | 99 | 5 | | 2 | 100 | 6 |
得到上面這種數據,我們就可以很方便的取每門課程前幾名,或者取最高,最低分數.
-
如果需要把最高的分數顯示爲1,第二的分數顯示爲2,只需要將語句中的
>
大於號改成<
小於號即可 如果還不能理解的話,建議一步一步加條件查看實際表的數據,來體會每一條條件語句的作用
先看
select *
from score as s1
inner join score as s2
on s1.course_id = s2.course_id ;
再看
select *
from score as s1
inner join score as s2
on s1.course_id = s2.course_id and s1.score >= s2.score;
然後是
select s1.course_id,s1.score,count(s2.score)
from score as s1
inner join score as s2
on s1.course_id = s2.course_id and s1.score >= s2.score
group by s1.course_id,s1.score;
最後是
select s1.course_id,s1.score,count(distinct s2.score)
from score as s1
inner join score as s2
on s1.course_id = s2.course_id and s1.score >= s2.score
group by s1.course_id,s1.score;