MySQL查询最大值(最小值)或前n个最大(最小)值的方法分析
在实际中,我们可能会有这样的需求,就是从数据库中查出某个字段的最大值或最小值,或者查出前n个最大(最小)值。例如,查出某个学生成绩中最好的一个或者查出排名在前5名的学生成绩等。下面简要给出一些示例查询代码。我们的表结构如下图:stuname字段相当于学生的姓名,score代表分数,id为主键 ;表数据准备如下:一、查询最大(最小值)在这里我们要分别查询出某个学生中的分数...
在实际中,我们可能会有这样的需求,就是从数据库中查出某个字段的最大值或最小值,或者查出前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
stuname
stuscore b ON a.=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
为过滤条件(这里取出最大和次大的分数值),就可以得到正确的结果集了。
更多推荐
所有评论(0)