MySQL複雜查詢:連線查詢+取某個型別的最大值
需求
假設有一個考試,比如CET(包括CET-4和CET-6),學生可以多次報考刷分。現在某教育單位要從考試結果中把每個學生的CET-6最高分拿出來,然後進行一個排名。
表結構
現在有兩個資料表:student 和 exam_result,分別表示學生的基本資訊和每次考試結果(包括CET-4和CET-6的結果)。
這裡不考慮表結構的優化和完整,只給出必要欄位。
student:
欄位名 | 含義 |
---|---|
id | ID(主鍵) |
name | 姓名 |
exam_result:
欄位名 | 含義 |
---|---|
id | ID(主鍵) |
cetVersion | CET版本或等級(CET-4還是CET-6) |
studentId | 學生ID |
score | 成績 |
分析
step 1
先嚐試把兩個表關聯起來,LEFT JOIN
左連線還記得嗎?(連線查詢不是關聯查詢)
SELECT exam_result.studentId, student.name, exam_result.cetVersion, exam_result.score FROM exam_result LEFT JOIN student ON (exam_result.studentId=student.id)
step 2
可是我們要的是CET-6的呀,那就在末尾加上 WHERE exam_result.cetVersion=6
吧。千萬不要加在FROM
後面,語法檢查都不給你通過,更不要談查資料啦。
於是我們就能清晰的看到,只有張三、李四和六神(SixGod)同學參加了六級考試,其中張三還考了兩次。
step 3
a
不忙著排序,這個等拿到想要的資料後再來。
先想想怎麼“過濾”一下,把每個人多出來的考試記錄去掉,只留下最高分的記錄。分開來看,就是怎麼去重和怎麼取最大值的問題。
如果你在搜尋引擎上搜索“SQL去重”的話,可能會給出DISTINCT
辦法,但在:DISTINCT
是嚴格的按照查詢欄位去重的,相當於你把查詢欄位都加入了主鍵,然後以主鍵唯一作為條件進行查詢。比如:SELECT DISTINCT studentId from exam_result
studentId
;但是隻查詢一個studentId
欄位幾乎是毫無意義的,還要加上其他欄位:SELECT DISTINCT studentId, score from exam_result
,你以為會在studentId
去重的基礎上加上score
欄位?NO!結果是:(studentId 不唯一) && ( score 不唯一)
,SQL語句加括號也沒用!
b
建議採用GROUP BY
進行去重。在【step 2】的基礎上,再在末尾新增GROUP BY exam_result.studentId
就好了:
SELECT exam_result.studentId, student.name, exam_result.cetVersion, exam_result.score as score
FROM exam_result
LEFT JOIN student ON (exam_result.studentId=student.id)
WHERE exam_result.cetVersion=6
GROUP BY exam_result.studentId
step 4
你應該發現,【step 3】查詢出來的結果中,張三的並不是最高成績。因為預設情況下進行ORDER BY
,優先獲取的是id在前的記錄。
既然我們是要取最高成績,也就是取score
欄位的最大值,那麼有一個很巧地用法:借用SQL的MAX()
方法。
把【step 2】中的exam_result.score
換成MAX(exam_result.score) as score
,也就是把“查詢成績”換成“查詢最好成績”。
於是我們順利的拿到了想要的結果:“從考試結果中把每個學生的CET-6最高分拿出來”;還差“然後進行一個排名”,你應該想到用ORDER BY
方法了,最終拼拼湊湊弄出了這麼個東西,它能“從考試結果中把每個學生的CET-6最高分拿出來,然後進行一個排名”:
SELECT exam_result.studentId, student.name, MAX(exam_result.score) as score
FROM exam_result
LEFT JOIN student ON (exam_result.studentId=student.id)
WHERE exam_result.cetVersion=6
GROUP BY exam_result.studentId
ORDER BY MAX(exam_result.score) DESC
在這個SQl語句中,其實可以簡寫很多部分,比如把ORDER BY MAX(exam_result.score)
簡寫成ORDER BY MAX(score)
,畢竟已經在第一行聲明瞭MAX(exam_result.score) as score
。
結語
在【step 3】【b】開頭,我寫了“建議採用GROUP BY
進行去重”,為什麼是“建議”呢?其實DISTINCT
也是可以做到我們需要的效果的,但是相對來說比較繁瑣,要先在exam_result表內使用UNION
合併兩個查詢結果,然後再去JOIN
連線student表。具體的可以Google關鍵詞【distinct multiple fields】或者【distinct multiple columns】。