rank/dense_rank/row_number

三者的区别:


rank/dense_rank/row_number_第1张图片
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,这样按照同样的逻辑向后执行。


rank/dense_rank/row_number_第2张图片
image.png

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

对于下表进行相关计算。


rank/dense_rank/row_number_第3张图片
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;
rank/dense_rank/row_number_第4张图片
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;
rank/dense_rank/row_number_第5张图片
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;
rank/dense_rank/row_number_第6张图片
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;
rank/dense_rank/row_number_第7张图片
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;
rank/dense_rank/row_number_第8张图片
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;
rank/dense_rank/row_number_第9张图片
image.png

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

你可能感兴趣的:(rank/dense_rank/row_number)