创建测试表
create table tmp_ma(
class string comment'品类',
brand string comment'品牌',
sales int comment'销量'
)
插入测试数据
insert into tmp_ma(class,brand,sales) values('手机','小米',10);
insert into tmp_ma(class,brand,sales) values('手机','华为',9);
insert into tmp_ma(class,brand,sales) values('手机','荣耀',6);
insert into tmp_ma(class,brand,sales) values('手机','一加',13);
insert into tmp_ma(class,brand,sales) values('手机','诺基亚',2);
insert into tmp_ma(class,brand,sales) values('手机','锤子',15);
insert into tmp_ma(class,brand,sales) values('电脑','小米',3);
insert into tmp_ma(class,brand,sales) values('电脑','华为',3);
insert into tmp_ma(class,brand,sales) values('电脑','联想',20);
insert into tmp_ma(class,brand,sales) values('电脑','戴尔',15);
insert into tmp_ma(class,brand,sales) values('电脑','华硕',15);
insert into tmp_ma(class,brand,sales) values('电脑','三星',10);
需求,按照品类分组,取出销量前3的品牌来。
分析,我们先手动的排名,在手机这个品类里,每个品牌的销量都不同,没有并列的情况,这是我们最想看到的情况,但是在
电脑这个品类里,戴尔和华硕并列排名第2,如果只取每个品牌的销量的前3的3条记录,那么电脑里,只取,联想,戴尔,华硕就够了。
select
k.*
from (
select
ROW_NUMBER() OVER(PARTITION BY t.class ORDER BY t.sales desc) MM
,t.*
from tmp_ma t
) k
where k.mm<=3;
另一种写法:
select
k.*
from (
select
rank() OVER(PARTITION BY t.class ORDER BY t.sales desc) MM
,t.*
from tmp_ma t
) k
where k.mm<=3;
如果,并列的联想和华硕算第2名,还需向下取出第3名来。
select
k.*
from (
select
DENSE_RANK() OVER(PARTITION BY t.class ORDER BY t.sales desc) MM
,t.*
from tmp_ma t
) k
where k.mm<=3;
总结:ROW_NUMBER(),RANK(),DENSE_RANK() 这3种排名的差异
1,ROW_NUMBER()
如上图,戴尔和华硕的销量虽然都是15,但是排名,戴尔是第2,华硕是第3,这个方法,可以避免取重复数据,例如我只想从排名第2里取出一条数据就行,那么这个方法只会取到戴尔。
有的时候,我们只会取最新的一条记录,那么建议使用这个方法,避免了取重复数据。
2,RANK()
这个方法,会把戴尔和华硕排名都为第2,因为有两个并列第2,那么就不会出现排名是3的记录,如果有3个排名第2的,那么就不会出现排名是3,4的记录。
3,DENSE_RANK()
这个方法,会把戴尔和华硕排名都为第2,三星排名是第3。
简单记忆法:
ROW_NUMBER() 无并列无跳跃排名
RANK() 有并列有跳跃排名
DENSE_RANK() 有并列无跳跃排名
over()里头的分组以及排序的执行晚于 where 、group by、 order by 的执行。
ROW_NUMBER()函数作用就是将select查询到的数据进行排序,每一条数据加一个序号,一般多用于分页查询。
RANK()函数,顾名思义排名函数,可以对某一个字段进行排名,这里为什么和ROW_NUMBER()不一样那,ROW_NUMBER()是排序,当存在相同销量时,ROW_NUMBER()会依次进行排序,他们序号不相同,而Rank()则不一样出现相同的,他们的排名是一样的。
DENSE_RANK()函数也是排名函数,和RANK()功能相似,也是对字段进行排名,那它和RANK()到底有什么不同那?DENSE_RANK()排名是连续的,RANK()是跳跃的排名,所以一般情况下用的排名函数就是RANK()。
实际编程中,根据需要,选择合适的方法。