【原创】MySQL 实现Oracle或者PostgreSQL的row_number over 这样的排名语法

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:

PostgreSQL 和Oracle 都提供了 row_number() over() 这样的语句来进行对应的字段排名, 很是方便。  MySQL却没有提供这样的语法。

最近由于从Oracle 迁移到MySQL的需求越来越多,所以这样的转化在所难免。 下面我在MySQL里面来实现这样的做法。


这次我提供的表结构如下,

1
2
3
4
5
                Table  "ytt.t1"
  Column  |         Type          | Modifiers
--------+-----------------------+-----------
  i_name |  character  varying (10) |  not  null
  rank   |  integer                not  null

我模拟了20条数据来做演示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
t_girl=#  select  from  t1  order  by  i_name;                           
  i_name  | rank
---------+------
  Charlie |   12
  Charlie |   12
  Charlie |   13
  Charlie |   10
  Charlie |   11
  Lily|    6
  Lily|    7
  Lily |    7
  Lily|    6
  Lily|    5
  Lily    |    7
  Lily    |    4
  Lucy    |    1
  Lucy    |    2
  Lucy    |    2
  Ytt     |   14
  Ytt     |   15
  Ytt     |   14
  Ytt     |   14
  Ytt     |   15
(20  rows )


在PostgreSQL下,我们来对这样的排名函数进行三种不同的执行方式1:

第一种,完整的带有排名字段以及排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
t_girl=#  select  i_name,rank, row_number() over(partition  by  i_name  order  by  rank  desc as  rank_number  from  t1; 
  i_name  | rank | rank_number
---------+------+-------------
  Charlie |   13 |           1
  Charlie|   12 |           2
  Charlie|   12 |           3
  Charlie|   11 |           4
  Charlie|   10 |           5
  Lily|    7 |           1
  Lily|    7 |           2
  Lily|    7 |           3
  Lily|    6 |           4
  Lily|    6 |           5
  Lily|    5 |           6
  Lily|    4 |           7
  Lucy|    2 |           1
  Lucy|    2 |           2
  Lucy|    1 |           3
  Ytt|   15 |           1
  Ytt|   15 |           2
  Ytt|   14 |           3
  Ytt|   14 |           4
  Ytt|   14 |           5
(20  rows )


第二种,带有完整的排名字段但是没有排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
t_girl=#  select  i_name,rank, row_number() over(partition  by  i_name )  as  rank_number  from  t1;
  i_name  | rank | rank_number
---------+------+-------------
  Charlie |   12 |           1
  Charlie|   12 |           2
  Charlie|   13 |           3
  Charlie|   10 |           4
  Charlie|   11 |           5
  Lily|    6 |           1
  Lily|    7 |           2
  Lily|    7 |           3
  Lily|    6 |           4
  Lily|    5 |           5
  Lily|    7 |           6
  Lily|    4 |           7
  Lucy|    1 |           1
  Lucy|    2 |           2
  Lucy|    2 |           3
  Ytt|   14 |           1
  Ytt|   15 |           2
  Ytt|   14 |           3
  Ytt|   14 |           4
  Ytt|   15 |           5
(20  rows )


第三种, 没有任何排名字段,也没有任何排序字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
t_girl=#  select  i_name,rank, row_number() over()  as  rank_number  from  t1;
  i_name  | rank | rank_number
---------+------+-------------
  Lily |    7 |           1
  Lucy|    2 |           2
  Ytt|   14 |           3
  Ytt|   14 |           4
  Charlie|   12 |           5
  Charlie|   13 |           6
  Lily|    7 |           7
  Lily|    4 |           8
  Ytt|   14 |           9
  Lily|    6 |          10
  Lucy|    1 |          11
  Lily|    7 |          12
  Ytt|   15 |          13
  Lily|    6 |          14
  Charlie|   11 |          15
  Charlie|   12 |          16
  Lucy|    2 |          17
  Charlie|   10 |          18
  Lily|    5 |          19
  Ytt|   15 |          20
(20  rows )


MySQL 没有提供这样的语句,所以我用了以下的存储过程来实现。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
DELIMITER $$
USE `t_girl`$$
DROP  PROCEDURE  IF EXISTS `sp_rownumber`$$
CREATE   PROCEDURE  `sp_rownumber`(
     IN  f_table_name  VARCHAR (64),
     IN  f_column_partitionby  VARCHAR (64),
     IN  f_column_orderby  VARCHAR (64),
     IN  f_is_asc  CHAR (4)
     )
BEGIN
       -- Created by ytt at 2014/1/10
       -- Do a row_number() over()
       DECLARE  INT ;
       -- Create a temporary table to save result.
       DROP  TABLE  IF EXISTS tmp_rownum;
       SET  @stmt = CONCAT( 'create temporary table tmp_rownum select *,' 'rownum' ' from ' ,f_table_name, ' where 1 = 0' );
       PREPARE  s1  FROM  @stmt;
       EXECUTE  s1;
       SET  i = 0;
       SET  @j = 0;
       SET  @v_column_paritionby =  '' ;
       -- Check whether  parition column is null or not.
       IF (f_column_partitionby =  ''  OR  f_column_partitionby  IS  NULL THEN
          -- No additional parition column.
SET  @stmt = CONCAT( 'insert into tmp_rownum select *,@j:= @j+1 as rownum from ' ,
f_table_name);
PREPARE  s1  FROM  @stmt;
EXECUTE  s1;
       ELSE
        -- Give partition column.
SET  @stmt = CONCAT( 'select count(*) from (select count(*) from ' ,f_table_name, ' group by ' ,
f_column_partitionby, ') as a into @cnt' );
PREPARE  s1  FROM  @stmt;
EXECUTE  s1;
         WHILE i < @cnt
         DO      
   -- Get the partition value one by one.
   SET  @stmt = CONCAT( 'select ' ,f_column_partitionby, ' from ' ,f_table_name, ' group by  ' ,f_column_partitionby, ' limit ' ,i, ',1 into @v_column_partitionby' );
   PREPARE  s1  FROM  @stmt;
   EXECUTE  s1;
   -- Check whether sort is needed.
           IF f_column_orderby =  ''  OR  f_column_orderby  IS  NULL  THEN
             SET  @stmt = CONCAT( 'insert into tmp_rownum select *,@j:= @j+1 as rownum from ' ,
f_table_name, ' where ' ,f_column_partitionby, ' = ' '' ,@v_column_partitionby, '' '' );
   ELSE
     SET  @stmt = CONCAT( 'insert into tmp_rownum select *,@j:= @j+1 as rownum from ' ,
f_table_name, ' where ' ,f_column_partitionby, ' = ' '' ,@v_column_partitionby, '' '
order by ' ,f_column_orderby, ' ' ,f_is_asc);
           END  IF;
           SET  @j = 0;
   PREPARE  s1  FROM  @stmt;
   EXECUTE  s1;
           SET  i = i + 1;
         END  WHILE;
       END  IF;
       -- Reset all session variables.
       SET  @j =  NULL ;
       SET  @v_column_paritionby =  NULL ;
       SET  @cnt =  NULL ;
       SELECT  FROM  tmp_rownum;
     END $$
DELIMITER ;


我们同样来执行第一种,第二种以及第三种查询,结果如下:

第一种,

CALL sp_rownumber('t1','i_name','rank','desc');

query result

i_name rank rownum
Charlie 13 1
Charlie 12 2
Charlie 12 3
Charlie 11 4
Charlie 10 5
Lily 7 1
Lily 7 2
Lily 7 3
Lily 6 4
Lily 6 5
Lily 5 6
Lily 4 7
Lucy 2 1
Lucy 2 2
Lucy 1 3
Ytt 15 1
Ytt 15 2
Ytt 14 3
Ytt 14 4
Ytt 14 5

第二种,


query result

i_name rank rownum
Charlie 12 1
Charlie 13 2
Charlie 11 3
Charlie 12 4
Charlie 10 5
Lily 7 1
Lily 7 2
Lily 4 3
Lily 6 4
Lily 7 5
Lily 6 6
Lily 5 7
Lucy 2 1
Lucy 1 2
Lucy 2 3
Ytt 14 1
Ytt 14 2
Ytt 14 3
Ytt 15 4
Ytt 15 5

第三种,


query result

i_name rank rownum
Lily 7 1
Lucy 2 2
Ytt 14 3
Ytt 14 4
Charlie 12 5
Charlie 13 6
Lily 7 7
Lily 4 8
Ytt 14 9
Lily 6 10
Lucy 1 11
Lily 7 12
Ytt 15 13
Lily 6 14
Charlie 11 15
Charlie 12 16
Lucy 2 17
Charlie 10 18
Lily 5 19
Ytt 15 20



本文转自 david_yeung 51CTO博客,原文链接:http://blog.51cto.com/yueliangdao0608/1350445,如需转载请自行联系原作者

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
4月前
|
SQL 关系型数据库 MySQL
MySQL探索:详解WITH AS语法的使用。
总的来说,MySQL的 `WITH AS`语法就如同我们路途中的导航设备,能帮助我们更好地组织和简化查询, 增强了我们和数据沟通的能力,使得复杂问题变得可控且更有趣。不论是在森林深处,还是在数据的海洋中,都能找到自己想要的路途和方向。
519 12
|
5月前
|
Oracle 关系型数据库 MySQL
Oracle linux 8 二进制安装 MySQL 8.4企业版
Oracle linux 8 二进制安装 MySQL 8.4企业版
160 1
|
9月前
|
SQL 存储 关系型数据库
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
本文详细介绍了MySQL中的SQL语法,包括数据定义(DDL)、数据操作(DML)、数据查询(DQL)和数据控制(DCL)四个主要部分。内容涵盖了创建、修改和删除数据库、表以及表字段的操作,以及通过图形化工具DataGrip进行数据库管理和查询。此外,还讲解了数据的增、删、改、查操作,以及查询语句的条件、聚合函数、分组、排序和分页等知识点。
773 55
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
|
7月前
|
SQL Oracle 关系型数据库
MySQL 和 Oracle 的区别?
本文对比了Oracle和MySQL数据库的多个方面。Oracle适用于大型数据库,支持高并发和大访问量,市场占有率为40%,安装占用空间较大,约3G;而MySQL适合中小型应用,是开源免费的,安装仅需152M。两者在主键生成、字符串处理、SQL语句、事务处理等方面存在差异。Oracle功能更为强大,尤其在企业级应用中表现突出,而MySQL则以简单易用见长。
825 7
MySQL 和 Oracle 的区别?
|
6月前
|
Oracle 关系型数据库 MySQL
使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试
这篇文章是作者尚雷关于使用崖山YMP迁移Oracle/MySQL至YashanDB 23.2的验证测试分享。介绍了YMP的产品信息,包括架构、版本支持等,还详细阐述了外置库部署、YMP部署、访问YMP、数据源管理、任务管理(创建任务、迁移配置、离线迁移、校验初始化、一致性校验)及MySQL迁移的全过程。
|
8月前
|
监控 Oracle 关系型数据库
Mysql、Oracle审计日志的开启
通过上述步骤,可以在 MySQL 和 Oracle 数据库中启用和配置审计日志。这些日志对于监控数据库操作、提高安全性和满足合规性要求非常重要。确保正确配置审计参数和策略,定期查看和分析审计日志,有助于及时发现并处理潜在的安全问题。
428 11
|
9月前
|
存储 SQL 关系型数据库
【MySQL基础篇】MySQL约束语法
文章介绍了MySQL中表的约束概念,包括非空、唯一、主键、默认和外键约束,以及如何在创建和修改表时指定这些约束。外键约束用于保持数据的一致性和完整性,文章通过示例展示了添加、删除外键的语法,并讨论了不同的删除/更新行为,如CASCADE和SETNULL。
【MySQL基础篇】MySQL约束语法
|
11月前
|
SQL 存储 关系型数据库
mysql SQL必知语法
本文详细介绍了MySQLSQL的基本语法,包括SELECT、FROM、WHERE、GROUPBY、HAVING、ORDERBY等关键字的使用,以及数据库操作如创建、删除表,数据类型,插入、查询、过滤、排序、连接和汇总数据的方法。通过学习这些内容,读者将能更好地管理和操
232 0
|
11月前
|
SQL 关系型数据库 MySQL
Mysql(2)—SQL语法详解
SQL(Structured Query Language,结构化查询语言)是一种用于管理关系型数据库的标准编程语言。它主要用于数据的查询、插入、更新和删除等操作。SQL最初在1970年代由IBM的研究人员开发,旨在处理关系数据模型。
124 0
|
11月前
|
自然语言处理 关系型数据库 MySQL
MySQL数据库使用Match语法需要安装什么插件吗?
【10月更文挑战第1天】MySQL数据库使用Match语法需要安装什么插件吗?
207 0

推荐镜像

更多