MySQL分类排名和分组TOP N实例详解

目录
  • 表结构
  • 题目一:获取每个科目下前五成绩排名(允许并列)
    •  分析:
  • 题目二:获取每个科目下最后两名学生的成绩平均值
    • 分析:
  • 题目三:获取每个科目下前五成绩排名(不允许并列)
    •  分析:
      • 总结

        表结构

        学生表如下:

        create table `t_student` (
          `id` int not null auto_increment,
          `t_id` int default null comment '学科id',
          `score` int default null comment '分数',
          primary key (`id`)
        );

        数据如下: 

        题目一:获取每个科目下前五成绩排名(允许并列)

        允许并列情况可能存在如4、5名成绩并列情况,会导致取前4名得出5条数据,取前5名也是5条数据。

        select
        	s1.* 
        from
        	student s1
        	left join student s2 on s1.t_id = s2.t_id 
        	and s1.score < s2.score 
        group by
        	s1.id
        having
        	count( s2.id ) < 5 
        order by
        	s1.t_id,
        	s1.score desc

          ps:取前4名时

         分析:

        1.自身左外连接,得到所有的左边值小于右边值的集合。以t_id=1时举例,24有5个成绩大于他的(74、64、54、44、34),是第6名,34只有4个成绩大于他的,是第5名……74没有大于他的,是第一名。

        select
        	* 
        from
        	student s1
        	left join student s2 on s1.t_id = s2.t_id 
        	and s1.score < s2.score 

          2. 把总结的规律转换成sql表示出来,就是group by 每个student 的 id(s1.id),having统计这个id下面有多少个比他大的值(s2.id)

        select
        	s1.* 
        from
        	student s1
        	left join student s2 on s1.t_id = s2.t_id 
        	and s1.score < s2.score 
        group by
        	s1.id
        having
        	count( s2.id ) < 5 

         3. 最后根据 t_id 分类,score 倒序排序即可。

        题目二:获取每个科目下最后两名学生的成绩平均值

        取最后两名成绩

        select
        	s1.* 
        from
        	student s1
        	left join student s2 on s1.t_id = s2.t_id 
        	and s1.score > s2.score 
        group by
        	s1.id 
        having
        	count( s1.id )< 2 
        order by
        	s1.t_id,
        	s1.score

        并列存在情况下可能导致筛选出的同一t_id 下结果条数大于2条,但题目要求是取最后两名的平均值,多条平均后还是本身,故不必再对其处理,可以满足题目要求。 

         分组求平均值:

        select
        	t_id,avg(score)
        from
        	(
        	select
        		s1.*
        	from
        		student s1
        		left join student s2 on s1.t_id = s2.t_id 
        		and s1.score > s2.score
        	group by
        		s1.id 
        	having
        		count( s1.id )< 2 
        	order by
        		s1.t_id,
        		s1.score 
        	) tt 
        group by
        	t_id

        结果: 

        分析:

        1. 查询出所有t1.score>t2.score 的记录

        select
        		s1.*,s2.*
        	from
        		student s1
        		left join student s2 on s1.t_id = s2.t_id 
        		and s1.score > s2.score

        2. group by s.id 去重,having 计数取2条

        3. group by t_id 分别取各自学科的然后avg取均值

        题目三:获取每个科目下前五成绩排名(不允许并列)

        select
        	* 
        from
        	(
        	select
        		s1.*,
        		@rownum := @rownum + 1 as num_tmp,
        		@incrnum :=
        	case
        			
        			when @rowtotal = s1.score then
        			@incrnum 
        			when @rowtotal := s1.score then
        			@rownum 
        		end as rownum 
        	from
        		student s1
        		left join student s2 on s1.t_id = s2.t_id 
        		and s1.score > s2.score,
        		( select @rownum := 0, @rowtotal := null, @incrnum := 0 ) as it 
        	group by
        		s1.id 
        	order by
        		s1.t_id,
        		s1.score desc 
        	) tt 
        group by
        	t_id,
        	score,
        	rownum 
        having
        	count( rownum )< 5

         分析:

        1.引入辅助参数

        select
        	s1.*,
        	@rownum := @rownum + 1 as num_tmp,
        	@incrnum :=
        case
        		
        		when @rowtotal = s1.score then
        		@incrnum 
        		when @rowtotal := s1.score then
        		@rownum 
        	end as rownum 
        from
        	student s1
        	left join student s2 on s1.t_id = s2.t_id 
        	and s1.score > s2.score,
        	( select @rownum := 0, @rowtotal := null, @incrnum := 0 ) as it

        2.去除重复s1.id,分组排序

        select
        		s1.*,
        		@rownum := @rownum + 1 as num_tmp,
        		@incrnum :=
        	case
        			
        			when @rowtotal = s1.score then
        			@incrnum 
        			when @rowtotal := s1.score then
        			@rownum 
        		end as rownum 
        	from
        		student s1
        		left join student s2 on s1.t_id = s2.t_id 
        		and s1.score > s2.score,
        		( select @rownum := 0, @rowtotal := null, @incrnum := 0 ) as it 
        	group by
        		s1.id 
        	order by
        		s1.t_id,
        		s1.score desc 

         3.group by    t_id, score, rownum   然后 having 取前5条不重复的

        总结

        到此这篇关于mysql分类排名和分组top n实例详解的文章就介绍到这了,更多相关mysql分类排名 top n内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

        (0)
        上一篇 2022年3月21日
        下一篇 2022年3月21日

        相关推荐