暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 排序和变量

李二白 2021-06-24
605


    排序中常见的三种窗口函数:ROW_NUMBER(),RANK(),DENSE_RANK()

    ROW_NUMBER() :连续排名
    DENSE_RANK() :并列连续排名
    RANK() :并列跳跃排名
    复制

        mysql 8.0支持窗口函数了,氮素目前常用的版本中,还是不支持窗口函数的,所以接下来会介绍一下用变量来实现各种排序的方法。


        为了方便大家理解,可以先看一下接下来代码中会用到表结构:

      CREATE TABLE `scores` (
      `id` int(11) NOT NULL COMMENT 'ID',
      `name` varchar(255) DEFAULT NULL COMMENT '姓名',
      `course_id` varchar(255) DEFAULT NULL COMMENT '课程ID',
      `score` int(11) DEFAULT NULL COMMENT '成绩',
      PRIMARY KEY (`id`)
      ) ;
      复制

      以此表为基础,将通过处理两个问题来展示这三种排序方式各自的特点:

      1. 对成绩进行排名

      2. 根据课程分组后对成绩进行排名


      一.连续排名    

          相同的值,依旧按照连续数字进行排名

      1.1.用连续排名对成绩进行排名
      1--ROW_NUMBER()实现 窗口函数,mysql8.0以下版本不支持,了解一下就行
      2SELECT score,
      3ROW_NUMBER() OVER (ORDER BY score DESC) ranking
      4FROM SCORES;


      复制

      1--使用变量实现
      2-- :=是mysql中的赋值
      3--这里的cur_rank是先+1然后再赋值给自己
      4SELECT score, 
      5       (@cur_rank := @cur_rank + 1) ranking  
      6FROM SCORES s, 
      7(SELECT @cur_rank := 0) r
      8ORDER BY score DESC;


      复制

        

      1.2.用连续排名根据课程分组后对成绩进行排名
      1--ROW_NUMBER()结合PARTITION BY
      2SELECT t.course_id,
      3      t.score, 
      4      ROW_NUMBER() OVER(PARTITION BY t.course_id order by t.score DESCas ranking
      5FROM  SCORES t;

      复制

       

       1-- 变量和IF实现
      2-- 新增的@pre_rank用来记录courseid,通过IF语句判断每一行课程id和上一行是否相等
      3SELECT t.course_id,
      4      t.score, 
      5      @cur_rank :=IF(@pre_rank=course_id,@cur_rank+1,1as ranking,
      6      @pre_rank :=course_id
      7FROM SCORES t, 
      8(SELECT @cur_rank := 0,@pre_rank=null) r
      9order by course_id ASC,score DESC;
      10
      11-- 变量和CASE WHEN实现
      12SELECT t.course_id,
      13     t.score, 
      14     case when @pre_rank=course_id then @cur_rank:=@cur_rank+1 
      15          when @pre_rank :=course_id then @cur_rank:=1
      16       end as ranging
      17FROM SCORES t, 
      18(SELECT @cur_rank := 0,@pre_rank=null) r
      19order by course_id ASC,score DESC;


      复制


           IF语句 和 CASE WHEN语句 的效果是一样的,可以根据日常使用习惯自行选择,但在使用CASE WHEN语句 时要注意,不能直接用 CASE WHEN ... ELSE   。需要用when语句把变量的赋值写清楚。


      二.并列连续排名

          并列即相同的值,相同的值保留重复名次,遇到下一个不同值时,依然按照连续数字排名

      2.1.用并列连续排名对成绩进行排名
      1--DENSE_RANK()实现  窗口函数,mysql 8.0以下版本不支持
      2SELECT  num,
      3        DENSE_RANK() OVER(ORDER BY rank DESC
      4FROM SCORES;

      复制


       1--变量和IF实现
      2--这里的 @pre_rank变量用来记录成绩,然后通过IF语句判断和上一行的成绩是否相等
      3SELECT score,
      4IF(@pre_rank = score, @cur_rank, @cur_rank := @cur_rank + 1) ranking,
      5@pre_rank := score
      6FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank = NULL) r
      7ORDER BY score DESC;
      8
      9--变量和case when 
      10SELECT score,
      11       case when @pre_rank = score then @cur_rank -- 即@cur_rank:= @cur_rank
      12            when @pre_rank := score then @cur_rank := @cur_rank + 1
      13       as ranking
      14FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank = NULL) r
      15ORDER BY score DESC;


      复制


      2.2.用并列连续排名根据课程分组后对成绩进行排名
      1--DENSE_RANK() 结合PARTITION BY
      2SELECT course_id, 
      3       score,
      4       DENSE_RANK() OVER(PARTITION BY course_id ORDER BY score DESC)
      5FROM scores;


      复制

       1-- 变量和IF语句
      2-- @pre_rank 记录成绩, @pre_course_id 记录科目
      3-- 可以看出, 用来记录源数据的变量初始值一般是null
      4SELECT course_id,
      5       score,
      6       IF(@pre_rank = score, @cur_rank, @cur_rank := @cur_rank + 1),
      7       @pre_rank := score,
      8       IF(@pre_course_id = course_id, @cur_rank, @cur_rank := 1) ranking,
      9       @pre_course_id := course_id
      10FROM SCORES s, 
      11(SELECT @cur_rank := 0, @pre_rank = NULL,@pre_course_id := NULL) r
      12ORDER BY course_id ASC,score DESC;


      复制


      三.并列跳跃排名

         并列即相同的值,相同的值保留重复名次,遇到下一个不同值时,跳跃到总共的排名

      3.1.用并列跳跃排名对成绩进行排名
      1--RANK() 函数 窗口函数,mysql 8.0以下版本不支持
      2SELECT *,
      3       RANK() OVER(ORDER BY score DESC)
      4FROM SCORES;


      复制


       1-- 变量和 if 实现
      2-- 新增的@rank_counter用来记录原始排名
      3SELECT score,
      4       @rank_counter := @rank_counter + 1,
      5       IF(@pre_rank = score, @cur_rank, @cur_rank := @rank_counter) ranking,
      6       @pre_rank := score
      7FROM SCORES s, 
      8(SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0) r 
      9ORDER BY score DESC;
      10
      11-- 变量和CASE WHEN 实现
      12SELECT score,
      13       @rank_counter := @rank_counter + 1,
      14       case when @pre_rank = score then @cur_rank --即@cur_rank :=@cur_rank
      15            when @pre_rank := score then @cur_rank := @rank_counter
      16       end as ranking
      17FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0) r
      18ORDER BY score DESC;


      复制


      3.2.用并列跳跃排名根据课程分组后对成绩进行排名
      1--RANK()结合PARTITION BY
      2SELECT course_id, 
      3       score,
      4       RANK() OVER(PARTITION BY course_id ORDER BY score DESC)
      5FROM SCORES;

      复制


       1-- 变量和IF语句
      2SELECT course_id,
      3       score,
      4       @rank_counter := IF(@pre_course_id = s.course_id,@rank_counter + 1,1),
      5       IF(@pre_course_id = s.course_id,IF(@pre_rank = s.score, @cur_rank, @cur_rank := @rank_counter),@cur_rank := 1) ranking,
      6       @pre_rank := s.score,
      7       @pre_course_id := s.course_id
      8FROM SCORES s, 
      9(SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0,@cur_couse:=null) r
      10ORDER BY course_id ASC,score DESC;


      复制


      文章转载自李二白,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论