天天看点

mysql实现row_number()、rank()、dense_rank()函数功能

最近部门换了一款BI工具,因为要根据筛选条件动态选取TOP10、实现排序排名功能,需要在BI工具中写mysql数据库的脚本,因为要实现ow_number()、rank()、dense_rank()函数功能,看了网上的一些资料,感觉脚本和数据示例有点出入,在这里根据一个简单的临时表做一下总结。

临时表名:tmp_ss

示例数据:

mysql实现row_number()、rank()、dense_rank()函数功能

可以看到store_name是有重复值的,可以用这个字段的排名来看dense_rank()、rank()的实现。

(1) row_number()实现方法

SELECT  store_name 
,@rank := @rank +1 
,@val := store_name 
FROM tmp_ss , (SELECT @val := '' , @rank := 0 ) t1 
ORDER BY store_name
; 

           

这里@val、@rank是mysql的变量表示方法,我们这里先看运行结果:

mysql实现row_number()、rank()、dense_rank()函数功能

我们看到第二列也就是排序列是连续的,即使store_name相同。我们可以感受一下这两个变量值变化的规律,就好比是tmp_ss排序之后,有一个游标遍历每一行,然后没遍历一行,@rank自加1,然后会把每行store_name的值传给@val;这个和oracle中存储过程的游标是非常类似的。

(2)dense_rank()实现方法

SELECT  
	 @val
	,store_name 
	,@rank := IF(@val = store_name,@rank ,@rank +1) 
	,@val := store_name 
FROM tmp_ss , (SELECT @val := '' , @rank := 0 ) t1 
ORDER BY store_name
;
           

运行结果:

mysql实现row_number()、rank()、dense_rank()函数功能

我们可以看到store_name相同时,排名是相同的,且排名数字不跳跃,排名n后面跟的一定是n或者n+1。这里第一列在实际写生产脚本的时候是不必要的,这里列出来只是为了大家能够清楚的看到,当运行sql时,刚开始这个变量是没有值的,然后@val := store_name这个代码把每行store_name的传给@val,从上向下看每一行,我们的非常清晰的感受到这个程序的运行过程。

(3)rank()实现方法

SELECT store_name 
,@rownum := @rownum +1 
,@rank := IF(@val = store_name,@rank ,@rownum) 
,@val := store_name 
FROM tmp_ss , (SELECT @val := '' , @rank := 0 ,@rownum := 0 ) t1 
ORDER BY store_name
; 
           

运行结果:

mysql实现row_number()、rank()、dense_rank()函数功能

我们看到,实现rank()的时候用到了3个变量,比上面多了一个@rownum变量,这个变量没遍历一行就会自加1,跟行号一样,这样的话就能实现排名的跳跃。怎么理解呢?我们复习下dense_rank()和rank()的区别,举个例子如果有20行数据进行排名,排序列有重复值,那么dense_rank()排名的最大序号小于20,rank()排名的最大序号一定是20,也就是说dense_rank()总排名会减少,而rank()总排名不减少。

下面重点来看@rank := IF(@val = store_name,@rank ,@rownum) 这段判断语句,首先上一行的store_name是存在@val中的,如果@val跟游标所在的当前行store_name相同,则取@rank值,即与上一样的排名相同,如果不相同,那么就取这行的行号作为排名。

总结: 这篇文章重点讲解了mysql排名的具体实现方法,表达能力有限,而且例子乍一看可能会感觉有些绕,读者不妨建临时表亲手运行一下示例代码。

需要注意,在实现排序的时候,只能有2个表关联,且第二表是用于实现排序的表。

类似于

t1

left join t2 on xxx = xxx

left join (SELECT @val := ‘’ , @rank := 0 ) t3

on 1 =1

这样多表关联的情况,亲测并不能实现排序的功能。

继续阅读