当前位置:   article > 正文

mysql自动排序函数dense_rank() over()、rank() over()、row_num() over()用法和区别

dense_rank() over()

区别:

  • rank():是并列排序,会跳过重复序号
  • dense_rank():是并列排序,不会跳过重复序号
  • row_number():是顺序排序,不跳过任何一个序号,就是行号

用法:

数据准备:

  1. create table students(
  2. id int(11) auto_increment primary key,
  3. name varchar(50) not null,
  4. score int(4) not null
  5. );
  6. insert into students(name,score) values
  7. ('zhangsan', 100),
  8. ('lisi', 99),
  9. ('wangwu', 100),
  10. ('trx', 90),
  11. ('pjf', 99),
  12. ('wzm', 96);

查看下插入的数据:

  1. mysql> select * from students;
  2. +----+----------+-------+
  3. | id | name | score |
  4. +----+----------+-------+
  5. | 1 | zhangsan | 100 |
  6. | 2 | lisi | 99 |
  7. | 3 | wangwu | 100 |
  8. | 4 | trx | 90 |
  9. | 5 | pjf | 99 |
  10. | 6 | wzm | 96 |
  11. +----+----------+-------+

使用三种不同的方法进行排序:

  1. select
  2. id,
  3. name,
  4. rank() over(order by score desc) `rank`,
  5. row_number() over(order by score desc) `row_number`,
  6. dense_rank() over(order by score desc) `dense_rank`
  7. from students;
  8. --------------------------------- 结果 ------------------------------------
  9. +----+----------+-------+------+------------+------------+
  10. | id | name | score | rank | row_number | dense_rank |
  11. +----+----------+-------+------+------------+------------+
  12. | 1 | zhangsan | 100 | 1 | 1 | 1 |
  13. | 3 | wangwu | 100 | 1 | 2 | 1 |
  14. | 2 | lisi | 99 | 3 | 3 | 2 |
  15. | 5 | pjf | 99 | 3 | 4 | 2 |
  16. | 6 | wzm | 96 | 5 | 5 | 3 |
  17. | 4 | trx | 90 | 6 | 6 | 4 |
  18. +----+----------+-------+------+------------+------------+

 

那么,如何用一般的SQL实现这几个函数的效果呢?

(1) rank()是并列排序,会跳过重复序号

思路:外查询按分数降序排列,子查询查出大于当前成绩的个数+1,个数+就是排名

  1. select
  2. id,
  3. name,
  4. a.score,
  5. (select count(score)+1 from students where score > a.score) `rank`
  6. from students a
  7. order by score desc;
  8. --------------------------------- 结果 ------------------------------------
  9. +----+----------+-------+------+
  10. | id | name | score | rank |
  11. +----+----------+-------+------+
  12. | 1 | zhangsan | 100 | 1 |
  13. | 3 | wangwu | 100 | 1 |
  14. | 2 | lisi | 99 | 3 |
  15. | 5 | pjf | 99 | 3 |
  16. | 6 | wzm | 96 | 5 |
  17. | 4 | trx | 90 | 6 |
  18. +----+----------+-------+------+

(2) dense_rank() 是并列排序,不会跳过重复序号

思路:用外查询按分数降序排列,子查询查出大于等于当前成绩去重后的个数,这个个数就是当前分数的名次。

  1. select
  2. id,
  3. name,
  4. a.score,
  5. (select count(distinct score) from students where score >= a.score) as dense_rank
  6. from students a
  7. order by score desc;
  8. --------------------------------- 结果 ------------------------------------
  9. +----+----------+-------+------------+
  10. | id | name | score | dense_rank |
  11. +----+----------+-------+------------+
  12. | 1 | zhangsan | 100 | 1 |
  13. | 3 | wangwu | 100 | 1 |
  14. | 2 | lisi | 99 | 2 |
  15. | 5 | pjf | 99 | 2 |
  16. | 6 | wzm | 96 | 3 |
  17. | 4 | trx | 90 | 4 |
  18. +----+----------+-------+------------+

(3) row_number() 是顺序排序,不跳过任何一个序号,其实就是排序后的行号

思路:这种方式排序的关键在于如何获取行号,行号既是排名的名次

先看结论:

  1. select
  2. id,
  3. name,
  4. a.score,
  5. (@rowNum:=@rowNum+1) as row_number
  6. from students a,(select @rowNum:=0) b
  7. order by score desc;
  8. --------------------------------- 结果 ------------------------------------
  9. +----+----------+-------+------------+
  10. | id | name | score | row_number |
  11. +----+----------+-------+------------+
  12. | 1 | zhangsan | 100 | 1 |
  13. | 3 | wangwu | 100 | 2 |
  14. | 2 | lisi | 99 | 3 |
  15. | 5 | pjf | 99 | 4 |
  16. | 6 | wzm | 96 | 5 |
  17. | 4 | trx | 90 | 6 |
  18. +----+----------+-------+------------+

那么,如何获取行号?关键:自定义变量@rowNum:=0;

假设有这样的数据

  1. mysql> select id,name from students;
  2. +----+----------+
  3. | id | name |
  4. +----+----------+
  5. | 1 | zhangsan |
  6. | 2 | lisi |
  7. | 3 | wangwu |
  8. | 4 | trx |
  9. | 5 | pjf |
  10. | 6 | wzm |
  11. +----+----------+

再看

  1. mysql> SELECT @rowNum:=0;
  2. +------------+
  3. | @rowNum:=0 |
  4. +------------+
  5. | 0 |
  6. +------------+
  7. mysql> SELECT @rowNum:=1;
  8. +------------+
  9. | @rowNum:=1 |
  10. +------------+
  11. | 1 |
  12. +------------+

SELECT @rowNum:=0; 表示声明了一个叫rowNum的变量并赋值为0,这个变量名是自定义的,在sql中我们可以对这个变量进行计算,如:

  1. mysql> select (@rowNum:=@rowNum+1) as num from (SELECT @rowNum:=0) a;
  2. +------+
  3. | num |
  4. +------+
  5. | 1 |
  6. +------+
  7. mysql> select (@rowNum:=@rowNum+5) as num from (SELECT @rowNum:=0) a;
  8. +------+
  9. | num |
  10. +------+
  11. | 5 |
  12. +------+

此时 (SELECT @rowNum:=0) a 相当于一个临时表,如果将它与students表进行连接将会得到:

  1. mysql> select b.*,id,name from students a,(SELECT @rowNum:=0) b;
  2. +------------+----+----------+
  3. | @rowNum:=0 | id | name |
  4. +------------+----+----------+
  5. | 0 | 1 | zhangsan |
  6. | 0 | 2 | lisi |
  7. | 0 | 3 | wangwu |
  8. | 0 | 4 | trx |
  9. | 0 | 5 | pjf |
  10. | 0 | 6 | wzm |
  11. +------------+----+----------+

可以看到,b表只有一条数据,与a表连接后就有了a表的6条数据,如果我们对自定义变量@rowNum:进行+1操作,会有什么效果呢?

  1. mysql> select (@rowNum:=@rowNum+1) as num,id,name from students a,(SELECT @rowNum:=0) b;
  2. +------+----+----------+
  3. | num | id | name |
  4. +------+----+----------+
  5. | 1 | 1 | zhangsan |
  6. | 2 | 2 | lisi |
  7. | 3 | 3 | wangwu |
  8. | 4 | 4 | trx |
  9. | 5 | 5 | pjf |
  10. | 6 | 6 | wzm |
  11. +------+----+----------+
  12. 6 rows in set (0.00 sec)

这就达到了查询结果带行号的目的,我们推演一下两个表连接的过程:

  1. 一开始自定义变量@rowNum:=0,a表第一条数据(1,'zhangsan')与自定义变量join,不过我们取的是@rowNum:=@rowNum+1,即0+1,那么最终就会得到(1,1,'zhangsan')
  2. 此时自定义变量@rowNum:=1,a表第一条数据(2,'lisi')与自定义变量join,即1+1,那么最终得到(2,2,'lisi')
  3. ....(以此类推)

由此,我们就能得到sql查询带行号的结果。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/240815
推荐阅读
相关标签
  

闽ICP备14008679号