1. 程式人生 > >MySQL複雜查詢:連線查詢+取某個型別的最大值

MySQL複雜查詢:連線查詢+取某個型別的最大值

本文連結:https://blog.inchm.cn/default/38.html

需求

假設有一個考試,比如CET(包括CET-4和CET-6),學生可以多次報考刷分。現在某教育單位要從考試結果中把每個學生的CET-6最高分拿出來,然後進行一個排名。

表結構

現在有兩個資料表:student 和 exam_result,分別表示學生的基本資訊和每次考試結果(包括CET-4和CET-6的結果)。

這裡不考慮表結構的優化和完整,只給出必要欄位。

student:

欄位名 含義
id ID(主鍵)
name 姓名

Snipaste_2018-12-24_11-04-09.png

exam_result:

欄位名 含義
id ID(主鍵)
cetVersion CET版本或等級(CET-4還是CET-6)
studentId 學生ID
score 成績

Snipaste_2018-12-24_11-12-48.png

分析

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)

Snipaste_2018-12-24_11-15-44.png

step 2

可是我們要的是CET-6的呀,那就在末尾加上 WHERE exam_result.cetVersion=6 吧。千萬不要加在FROM後面,語法檢查都不給你通過,更不要談查資料啦。

於是我們就能清晰的看到,只有張三、李四和六神(SixGod)同學參加了六級考試,其中張三還考了兩次。

Snipaste_2018-12-24_11-23-05.png

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語句加括號也沒用!

Snipaste_2018-12-24_11-40-29.png

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

Snipaste_2018-12-24_11-46-54.png

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

Snipaste_2018-12-24_11-46-54.png

在這個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】。