美文网首页
MySQL查询各科成绩前三名的记录与排名的思路分析(不考虑并列)

MySQL查询各科成绩前三名的记录与排名的思路分析(不考虑并列)

作者: 牛奶加醋 | 来源:发表于2018-09-09 00:18 被阅读1430次
  • 表结构如下图
+-----+------------+-----------+-------+
| 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

      • 但是,理想是丰满的,现实却很骨感,由于相同分数情况的出现,单纯的去统计按照

        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;

相关文章

  • MySQL查询各科成绩前三名的记录与排名的思路分析(不考虑并列)

    表结构如下图 排名方法如下 首先将分数表score自连接按照第一个条件 s1.course_id = s2.cou...

  • 2020-11-19 初二班级家长会上的发言

    一、分析成绩: 我想:先看总成绩,再看各科成绩,了解在班级以及在年级的排名,学会分析,看学生的各科成绩,特别是学生...

  • mysql查询优化 - 慢查询

    mysql查询速度优化思路 开启慢查询日志 查看导致阻塞的sql语句 重现场景, 单独测试 mysql 慢查询分析...

  • MySQL之排行榜

    1、获取所有学生成绩排名-并列排名 2、获取所有学生成绩排名-超过你的人数个数 3、获取所有学生成绩排名,不是并列...

  • mysql 联表查询

    mysql 联表查询 JOIN 对比 思路: 1.分析需求,分析查询的字段来自哪些表(连接查询) 2.确定使用哪...

  • 在MySQL中实现Rank高级排名函数

    MySQL中没有Rank排名函数,当我们需要查询排名时,只能使用MySQL数据库中的基本查询语句来查询普通排名。尽...

  • 在MySQL中实现Rank高级排名函数 风澈vio

    MySQL中没有Rank排名函数,当我们需要查询排名时,只能使用MySQL数据库中的基本查询语句来查询普通排名。尽...

  • MySQL慢查询

    定义 分析MySQL语句查询性能的方法除了使用 EXPLAIN 输出执行计划,还可以让MySQL记录下查询超过指定...

  • MySQL查询性能问题排查

    Mysql数据库的性能问题排查是十分复杂的,具体方法视场景而定,这里只做大致思路分析。 1. 整体考虑导致查询性能...

  • MySQL中的慢查询

    在MySQL中,提供了对慢查询的语句的检测与记录能力。 MySQL的慢查询日志是MySQL提供的一种日志记录,用来...

网友评论

      本文标题:MySQL查询各科成绩前三名的记录与排名的思路分析(不考虑并列)

      本文链接:https://www.haomeiwen.com/subject/ihtrgftx.html