mysql5模拟oracle的row_number、dense_rank、rank功能

功能说明

  1. row_number() 是连续不重复的排序,可以利用它来实现分页,例如1,2,3,4,5,6
  2. dense_rank() 是连续排序,多个第二名仍然跟着第三名,例如1,2,2,3,4,5
  3. rank() 是跳跃排序,两个第一名下来就是第三名,三个第三名下来就是第六名,例如1,1,3,3,3,6

mysql8.0已原生支持,本篇文章仅会对mysql5.7及以前的版本

测试sql数据

CREATE TABLE g_stud (
  id varchar(30) NOT NULL,
  username varchar(30) NOT NULL,
  userscore int(11),
  usersubject varchar(30),
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

insert into g_stud (id, username, userscore, usersubject) values('1001','张三','98','语文');
insert into g_stud (id, username, userscore, usersubject) values('1002','张三','86','数学');
insert into g_stud (id, username, userscore, usersubject) values('1003','张三','86','英语');
insert into g_stud (id, username, userscore, usersubject) values('1004','张三','73','物理');
insert into g_stud (id, username, userscore, usersubject) values('1005','李四','85','语文');
insert into g_stud (id, username, userscore, usersubject) values('1006','李四','92','数学');
insert into g_stud (id, username, userscore, usersubject) values('1007','李四','79','英语');
insert into g_stud (id, username, userscore, usersubject) values('1008','李四','79','物理');
insert into g_stud (id, username, userscore, usersubject) values('1009','王五','68','语文');
insert into g_stud (id, username, userscore, usersubject) values('1010','王五','79','数学');
insert into g_stud (id, username, userscore, usersubject) values('1011','王五','92','英语');
insert into g_stud (id, username, userscore, usersubject) values('1012','王五','92','物理');

无分组row_number

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    (@rownum:=@rownum + 1) rn
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY userscore desc, id) s,
    (select @rownum:=0) r
 ) s

无分组dense_rank

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    if(@sc=s.userscore, @dense_rank:=@dense_rank, @dense_rank:=@dense_rank + 1) rn,
    @sc:=s.userscore
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY userscore desc, id) s,
    (select @sc:=null, @dense_rank:=0) r
) s

无分组rank

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    @rownum:=@rownum + 1,
    if(@sc=s.userscore, @rank:=@rank, @rank:=@rownum) rn,
    @sc:=s.userscore
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY userscore desc, id) s,
    (select @sc:=null, @rownum:=0, @rank:=0) r
) s

分组row_number

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    if(@uname=s.username, @rownum:=@rownum + 1, @rownum:=1) rn,
    @uname:=s.username
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY username, userscore desc, id) s,
    (select @uname:=null, @rownum:=0) r
) s

分组dense_rank

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    if(@uname=s.username, if(@sc=s.userscore, @dense_rank:=@dense_rank, @dense_rank:=@dense_rank + 1), @dense_rank:=1) rn,
    @uname:=s.username,
    @sc:=s.userscore
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY username, userscore desc, id) s,
    (select @uname:=null, @sc:=null, @dense_rank:=0) r
) s

分组rank

SELECT
  s.id, s.username, s.userscore, s.usersubject, s.rn
FROM (
  SELECT
    s.id, s.username, s.userscore, s.usersubject,
    if(@uname=s.username, @rownum:=@rownum + 1, @rownum:=1),
    if(@sc=s.userscore, @rank:=@rank, @rank:=@rownum) rn,
    @uname:=s.username,
    @sc:=s.userscore
  FROM
    (SELECT id, username, userscore, usersubject FROM g_stud ORDER BY username, userscore desc, id) s,
    (select @uname:=null, @sc:=null, @rownum:=0, @rank:=0) r
) s

注意事项

  • 必须先对数据order by, 并且order by字段必须确定唯一的行,否则mysql可能排序失效。所以order by最后一个字段加了个id
  • 注意select子句变量计算列的先后顺序,因为select子句的字段是按从左到右执行的,否则rn列的查询结果必然错误。所以顺序为@rownum、(@dense_rank 或 @rank)、(@uname | @sc),其中@uname、@sc顺序可以互换。当然,变量初始化顺序是可以随意的。
  • 注意:if函数的第一个参数@uname=s.username或@sc=s.userscore是没有冒号的,有冒号的是赋值语句
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值