1. 程式人生 > >MySQL查詢最大值(最小值)或前n個最大(最小)值的方法分析

MySQL查詢最大值(最小值)或前n個最大(最小)值的方法分析

在實際中,我們可能會有這樣的需求,就是從資料庫中查出某個欄位的最大值或最小值,或者查出前n個最大(最小)值。例如,查出某個學生成績中最好的一個或者查出排名在前5名的學生成績等。下面簡要給出一些示例查詢程式碼。

我們的表結構如下圖:
這裡寫圖片描述

stuname欄位相當於學生的姓名,score代表分數,id為主鍵 ;
表資料準備如下:
這裡寫圖片描述
一、查詢最大(最小值)
在這裡我們要分別查詢出某個學生中的分數的最大值,這裡可有兩種查詢方法。
1

SELECT a.stuname,MAX(a.score) AS score FROM stuscore a  GROUP BY a.`stuname`
;

在這個語句中,我們通過對stuname欄位進行分組,然後再用MAX()函式對每組中的最大值進行計算。
2、使用連線

SELECT a.stuname,a.score AS score FROM stuscore a JOIN 
stuscore b ON a.`stuname`=b.`stuname` 
 GROUP BY a.`score` HAVING a.`score`=MAX(b.`score`);

在第二條sql語句中,我們以stuname為判斷條件,對兩個表進行連線操作。如果只執行SELECT a.stuname,a.score AS score FROM stuscore a JOIN
stuscore b ON a.

stuname=b.stuname我們會得到下面的結果集:
這裡寫圖片描述
之所以會得到這個結果集,是因為在連線時,左表中的每條記錄都會根據連線條件ON a.stuname=b.stuname“和右表中的每條記錄進行匹配,這就是為什麼會出現重複記錄的原因。這個有點像程式語言中的“雙重迴圈”。

然後再加分組和分組條件GROUP BY a.score HAVING a.score=MAX(b.score),就可以得到每個學生中的最大分數;
這裡寫圖片描述
其實GROUP BY a.`score ` HAVING a.`score`=MAX(b.`score`)這個分組條件一開始我也是有點不大理解,就是說我是根據score

欄位進行分組的,但這裡的MAX()函式為什麼就可以計算出每個學生中的最大分數,我們知道第一種方法比較好理解就是對每個學生的姓名分組,然後用MAX()函式計算出其中的最大值,這是肯定的,但第二方法是對score欄位進行分組的。在這裡我覺得原因應該是,在將兩個表進行連線時,連線條件a.stuname=b.stuname` 已經對這些記錄根據學生姓名進行分組了,所以MAX(b.score)`才可以計算出每個學生中的最大分數。
二、前n個最大(最小)值
在這裡,我要查詢出,每個學生中,排名前兩位的分數。大概思路是,對以姓名為分組的每條記錄,首先要查詢某個記錄在它所屬的組別中,所有大於該記錄的分數的記錄數,然後根據到的記錄數,就可以對這個結果集進行過慮了。首先來看程式碼和效果。

SELECT c.stuname,c.score FROM (SELECT a.stuname,a.score,(SELECT COUNT(*) FROM stuscore b WHERE b.score>a.score AND b.stuname=a.stuname) AS cnt 
FROM stuscore a ) c WHERE c.cnt<=1  GROUP BY c.stuname,c.score;

這裡寫圖片描述
這個確實得到了我們想要的結果集。
來分析 一下
在這個查詢中的SELECT a.stuname,a.score,(SELECT COUNT(*) FROM stuscore b WHERE b.score>a.score AND b.stuname=a.stuname) AS cnt
FROM stuscore a;
子查詢執行得到的結果集如下:
這裡寫圖片描述
cnt就是得到某個記錄在它所屬的組別中,所有大於該記錄的分數的記錄數。以姓名為zzz,分數為70的記錄為例,它的cnt值為1就代表在它所屬組別中,有1條記錄的分數比它高。其中cnt欄位的計算我們又可以通過一個子查詢來完成SELECT COUNT(*) FROM stuscore b WHERE b.score>a.score AND b.stuname=a.stuname,有了這個子查詢,當我們對每條記錄進行計算時,都要計算這個子查詢,這個子查詢的條件WHERE b.score>a.score AND b.stuname=a.stuname就是限定在某個組別中查詢比該條記錄分數大的記錄,同時通過COUNT()函式來計算符合條件的記錄數。
最後再根據得到的結果集進行過濾,以WHERE c.cnt<=1為過濾條件(這裡取出最大和次大的分數值),就可以得到正確的結果集了。