简介:在本教程中,您将学习如何在MySQL中模拟row_number()函数。我们将向您展示如何为结果集中的每一行或每组行添加唯一编号。

请注意,MySQL支持ROW_NUMBER()自8.0版以来的版本。如果您使用MySQL 8.0或更高版本,请检查它的ROW_NUMBER()功能。否则,您可以继续学习本教程以了解如何模拟ROW_NUMBER()功能。

row_number函数简介

这  row_number()是一个排名函数,它返回一行的序号,从第一行的1开始。您经常希望使用  row_number()函数来生成特定报告。

版本低于8.0的MySQL不支持row_number()就像Microsoft SQL Server,Oracle或PostgreSQL一样。幸运的是,MySQL提供了可用于模拟row_number()函数的会话变量  。

MySQL row_number - 为每一行添加一个行号

要模拟  row_number()函数,您必须在查询中使用会话变量。

以下语句从employees表中获取5名员工,  并从1开始为每行添加行号。

SET @row_number = 0;
SELECT
	( @row_number := @row_number + 1 ) AS num,
	firstName,
	lastName 
FROM
	employees 
	LIMIT 5; 
	
+------+-----------+-----------+
| num  | firstName | lastName  |
+------+-----------+-----------+
|    1 | Diane     | Murphy    |
|    2 | Mary      | Phan      |
|    3 | Jeff      | Firrelli  |
|    4 | William   | Patterson |
|    5 | Gerard    | Bondur    |
+------+-----------+-----------+
5 rows in set (0.00 sec)

在上面的陈述中:

  • 在第一个语句中,我们定义了一个名为的变量  row_number,并将其值设置为0.这row_number是由@前缀指示的会话变量。

  • 在第二个语句中,我们从employees表中选择数据,并将每行的  row_number变量值增加到1。LIMIT子句用于约束返回的行数,在这种情况下,它被设置为5。

另一种技术是使用会话变量作为派生表,并将其与主表交叉连接。请参阅以下查询:

SELECT 
    (@row_number:=@row_number + 1) AS num, firstName, lastName
FROM
    employees,(SELECT @row_number:=0) AS t
LIMIT 5;

请注意,派生表必须具有自己的别名,以使查询在语法上正确。


MySQL row_number - 为每个组添加行号

row_number() OVER PARTITION BY 功能怎么样  ?例如,如果要为每个组添加行号,并为每个新组重置行,怎么办?

我们来看看示例数据库中的payments表:

+----------------+
| payments       |
+----------------+
| customerNumber |
| checkNumber    |
| paymentDate    |
| amount         |
+----------------+
4 rows in set (0.00 sec)
SELECT
    customerNumber, paymentDate, amount
FROM
    payments
ORDER BY customerNumber; 

+----------------+-------------+-----------+
| customerNumber | paymentDate | amount    |
+----------------+-------------+-----------+
|            103 | 2014-10-19  |   6066.78 |
|            103 | 2013-06-05  |  14571.44 |
|            103 | 2014-12-18  |   1676.14 |
|            112 | 2014-12-17  |  14191.12 |
|            112 | 2013-06-06  |  32641.98 |
|            112 | 2014-08-20  |  33347.88 |
|            114 | 2013-05-20  |  45864.03 |
|            114 | 2014-12-15  |  82261.22 |
...

假设您为每个客户添加一个行号,并在客户编号更改时重置行号。

要实现此目的,您必须使用两个会话变量,一个用于行号,另一个用于存储旧客户编号,以将其与当前的客户编号进行比较,如下面的查询:

SELECT
	@row_number :=
	IF( @customer_no = customerNumber, @row_number + 1, 1 ) AS num,
	@customer_no := customerNumber AS CustomerNumber,
	paymentDate,
	amount 
FROM
	payments 
ORDER BY
	customerNumber; 
	
# 我们在查询中使用了IF函数。如果客户编号保持不变,我们增加了  row_number变量,否则,我们将其重置为1。
查询结果如下面的屏幕截图所示。

+------+----------------+-------------+-----------+
| num  | CustomerNumber | paymentDate | amount    |
+------+----------------+-------------+-----------+
|    1 |            103 | 2014-10-19  |   6066.78 |
|    2 |            103 | 2013-06-05  |  14571.44 |
|    3 |            103 | 2014-12-18  |   1676.14 |
|    1 |            112 | 2014-12-17  |  14191.12 |
|    2 |            112 | 2013-06-06  |  32641.98 |
|    3 |            112 | 2014-08-20  |  33347.88 |
|    1 |            114 | 2013-05-20  |  45864.03 |
|    2 |            114 | 2014-12-15  |  82261.22 |
|    3 |            114 | 2013-05-31  |   7565.08 |
|    4 |            114 | 2014-03-10  |  44894.74 |
|    1 |            119 | 2014-11-14  |  19501.82 |
|    2 |            119 | 2014-08-08  |  47924.19 |
|    3 |            119 | 2015-02-22  |  49523.67 |
...

与  row_number每行一样,您可以使用派生表和交叉连接技术来生成相同的结果。

SELECT 
    @row_number:=CASE
        WHEN @customer_no = customerNumber THEN @row_number + 1
        ELSE 1
    END AS num,
    @customer_no:=customerNumber as CustomerNumber,
    paymentDate,
    amount
FROM
    payments,(SELECT @customer_no:=0,@row_number:=0) as t
ORDER BY customerNumber;

在本教程中,我们向您展示了如何在MySQL中模拟row_number函数。


来源:https://www.begtut.com/mysql/mysql-row-number.html