美文网首页
rank/dense_rank/row_number

rank/dense_rank/row_number

作者: 酸甜柠檬26 | 来源:发表于2019-11-16 17:57 被阅读0次

    三者的区别:


    image.png

    关于变量和if实现rank

    SELECT s.score,
    @rank_counter := @rank_counter + 1 连续排名,
    IF(@pre_score = s.score, @cur_rank, @cur_rank := @rank_counter) ranking,
    @pre_score := s.score
    FROM score s, (SELECT @cur_rank :=0, @pre_score := NULL, @rank_counter := 0) r
    ORDER BY s.score DESC;
    

    逻辑:
    要明白rank的排序逻辑,如果是相同的数值,则并列排序,如果后面的值开始不一样,则跳跃排序,及1,1,3。那么有两个地方需要注意:1、并列排序时,让排序值ranking保持不变,2、跳跃排序时,让ranking为该数字在正常排名的位置,及row_number的那个位置。
    那么在代码里,from中设置的三个变量:1、@cur_rank是实现并列排序和跳跃排序两者的,也即在rank开窗函数中最终实现的排名,2、@pre_score为上一段的得分,把他放在if的后面进行:=s.score的赋值,比if里面的判断=s.score慢一步,就是为了让@pre_score等于上一段的分数,好来判断是否为并列排序,3、@rank_counter在这里被赋值为0,然后在select的第一个是@rank_counter:=@rank_counter+1,也就是给score的每一个分数都给一个连续排名,相当于row_number,他在这里的作用是为了给rank进行跳跃时得到他本来所处的位置数字。
    执行完from中的代码以后,开始执行select,注意order by是在select的后面执行的,但是赋值一直都是最后执行的,所以这段代码里,想筛选出score以后,进行order by排序,然后再进行相应的赋值。
    在if函数里,第一步,@pre_score为null,不等于score的第一个值99,所以为假,执行@cur_rank:=@rank_counter,得到1,然后再if的后面,@pre_score被赋值为score,此时@pre_score=99;第二步,@pre_score的98不等于score的98,为假,继续得到@cur_rank:=@rank_counter,得到2,同样第三步得到3,到了第四步,得到4,重点第5步,此时@pre_score=上一段的分数等于89,判断时,@pre_score也是等于此时这一段的score的89时,为真,返回@cur_rank,为4,这样按照同样的逻辑向后执行。


    image.png

    想明白它的逻辑,再设计相应变量来实现目的。

    对于下表进行相关计算。


    image.png

    一、不分组的情况下的rank/dense_rank/row_number
    1、(1)连续排名row_number() over(order by)
    对表中的所有的分数进行位置排名,没有并列名次的情况

    SELECT
        score,
        row_number ( ) over ( ORDER BY score DESC ) ranking 
    FROM
        score;
    

    (2)利用变量@和if来实现上面的开窗函数

    SELECT
        score,
        @i := @i + 1 ranking 
    FROM
        score,
        ( SELECT @i := 0 ) ranking 
    ORDER BY
        score DESC;
    
    image.png

    2、(1)并列跳跃排名rank() over(order by)

    SELECT
        score,
        rank ( ) over ( ORDER BY score DESC ) ranking 
    FROM
        score;
    

    (2)利用变量@和if来实现上面的开窗函数
    思路:如果分数一样,则排名相同,如果后面的分数不同,则排名为该值在该表中本来的排名位置。

    SELECT s.score,
    @rank_counter := @rank_counter + 1 连续排名,
    IF(@pre_score = s.score, @cur_rank, @cur_rank := @rank_counter) ranking,
    @pre_score := s.score
    FROM score s, (SELECT @cur_rank :=0, @pre_score := NULL, @rank_counter := 0) r
    ORDER BY s.score DESC;
    

    (3)使用case when来实现上面的开窗函数

    SELECT
        s.score,
        @rank_counter := @rank_counter + 1 连续排名,
        ( CASE WHEN @pre_score = s.score THEN @cur_rank 
                     WHEN @pre_score := s.score THEN @cur_rank := @rank_counter END ) ranking 
    FROM
        score s,
        ( SELECT @pre_score := NULL, @cur_rank := 0, @rank_counter := 0 ) ranking 
    ORDER BY
        score DESC;
    
    image.png

    3、(1)并列连续排名dense_rank() over(order by)

    select score,
    dense_rank() over(order by score desc) ranking
    from score;
    

    (2)利用变量@和if来实现上面的开窗函数

    SELECT
        score,
    IF
        ( @pre_score = score, @cur_rank, @cur_rank := @cur_rank + 1 ) ranking,
        @pre_score := score 
    FROM
        score,
        ( SELECT @pre_score := NULL, @cur_rank := 0 ) ranking 
    ORDER BY
        score DESC;
    

    (3)利用case when来实现上面的开窗函数

    SELECT
        score,
        ( CASE WHEN @pre_score = score THEN @cur_rank WHEN @pre_score := score THEN @cur_rank := @cur_rank + 1 END ) ranking 
    FROM
        score,
        ( SELECT @pre_score := NULL, @cur_rank := 0 ) ranking 
    ORDER BY
        score DESC;
    
    image.png

    二、分组的情况下的rank/dense_rank/row_number
    1、(1)连续排名row_number() over(partition by order by)

    SELECT
        course_id,
        score,
        row_number ( ) over ( PARTITION BY course_id ORDER BY score DESC ) ranking 
    FROM
        score 
    ORDER BY
        course_id;
    

    (2)使用变量@和if实现上面的开窗函数

    SELECT
        course_id,
        score,
    IF
        ( @pre_course_id = course_id, @cur_rank := @cur_rank + 1, @cur_rank := 1 ) ranking,
        @pre_course_id := course_id 
    FROM
        score,
        ( SELECT @pre_course_id := NULL, @cur_rank := 0 ) t 
    ORDER BY
        course_id ASC,
        score DESC;
    
    image.png

    2、(1)并列跳跃排名rank() over(partition by order by)

    SELECT
        course_id,
        score,
        rank ( ) over ( PARTITION BY course_id ORDER BY score DESC ) ranking 
    FROM
        score;
    

    (2)利用变量和if来实现上面的开窗函数

    SELECT
            course_id,
            score,
        IF
            ( @pre_course_id = course_id, @rank_count := @rank_count + 1, @rank_count := 1 ) t1, #辅助列,组内连续排名
        IF
            ( @pre_course_id = course_id,
            IF( @pre_score = score, @cur_rank, @cur_rank := @rank_count ),
            @cur_rank := 1 
            ) ranking, 
        @pre_course_id := course_id ,
        @pre_score := score 
            FROM
            score,
            ( SELECT @pre_course_id := NULL, @pre_score := NULL, @cur_rank := 0, @rank_count := 1 ) t2 
        ORDER BY
            course_id,
            score DESC;
    
    image.png

    3、(1)并列连续排名dense_rank() over(partition by order by)

    SELECT
        course_id,
        score,
        dense_rank ( ) over ( PARTITION BY course_id ORDER BY score DESC ) ranking 
    FROM
        score;
    

    (2)利用变量@和if来实现上面的开窗函数

    SELECT
        course_id,
        score,
    IF
        (
        @pre_course_id = course_id,
    IF
        ( @pre_score = score, @cur_rank, @cur_rank := @cur_rank + 1 ),
        @cur_rank := 1 
        ) ranking,
        @pre_course_id := course_id,
        @pre_score := score 
    FROM
        score,
        ( SELECT @pre_score := NULL, @pre_course_id := NULL, @cur_rank := 0 ) t 
    ORDER BY
        course_id,
        score DESC;
    
    image.png

    整理自:https://blog.csdn.net/u011726005/article/details/94592866#41__134

    相关文章

      网友评论

          本文标题:rank/dense_rank/row_number

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