三者的区别:
关于变量和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
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;
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;
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
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;
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;
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;
整理自:https://blog.csdn.net/u011726005/article/details/94592866#41__134