MariaDB ROW_NUMBER() 函数的基础用法与实例

MariaDB ROW_NUMBER() 函数用于为查询结果集中的每一行分配一个连续的行号。

发布于

MariaDB ROW_NUMBER() 函数用于为查询结果集中的每一行分配一个连续的行号。这个行号是基于指定的排序条件进行计算的。该函数常用于报表生成、分页查询等场景。

语法

MariaDB ROW_NUMBER() 函数的语法如下:

ROW_NUMBER() OVER ([PARTITION BY expr1,...] [ORDER BY expr2, ...])
  • PARTITION BY 子句用于指定分区表达式。该函数会为每个分区单独计算行号。
  • ORDER BY 子句用于指定行号的排序规则。在同一个分区内,行号按指定的排序顺序递增。

如果省略了 PARTITION BY,则对整个结果集计算行号。如果省略了 ORDER BY,则行号按任意顺序分配。

该函数会为每一行返回一个从 1 开始的行号。

实例

不分区,按照任意顺序编号

此示例演示了最简单的 ROW_NUMBER() 用法,为每一行编号。

DROP TABLE IF EXISTS mytable;
CREATE TABLE mytable (name VARCHAR(10), score INT);
INSERT INTO mytable VALUES
  ('John', 90), ('Amy', 92), ('Bob', 88), ('Kate', 95);

SELECT name, score, ROW_NUMBER() OVER() AS 'Row Number'
FROM mytable;

以下是该语句的输出:

+------+-------+------------+
| name | score | Row Number |
+------+-------+------------+
| Amy  |    92 |          1 |
| Bob  |    88 |          2 |
| John |    90 |          3 |
| Kate |    95 |          4 |
+------+-------+------------+

没有指定排序规则,所以行号随机分配。

不分区,按分数排序编号

此示例按分数升序为每一行编号。

SELECT name, score, ROW_NUMBER() OVER (ORDER BY score) AS 'Row Number'
FROM mytable;

以下是该语句的输出:

+------+-------+------------+
| name | score | Row Number |
+------+-------+------------+
| Bob  |    88 |          1 |
| John |    90 |          2 |
| Amy  |    92 |          3 |
| Kate |    95 |          4 |
+------+-------+------------+

按姓名分区,分数降序编号

此示例按姓名分区,并在每个分区内按分数降序编号。

SELECT name, score,
    ROW_NUMBER() OVER (PARTITION BY name ORDER BY score DESC) AS 'Row Number'
FROM mytable;

以下是该语句的输出:

+------+-------+------------+
| name | score | Row Number |
+------+-------+------------+
| Amy  |    92 |          1 |
| Bob  |    88 |          1 |
| John |    90 |          1 |
| Kate |    95 |          1 |
+------+-------+------------+

每个名字作为一个分区,分区内按分数降序排列并编号。

按城市和薪资级别分区编号

此示例模拟为一个公司的员工按城市和薪资级别编号。

DROP TABLE IF EXISTS employees;
CREATE TABLE employees (
  name VARCHAR(20),
  city VARCHAR(20),
  salary DECIMAL(10,2)
);

INSERT INTO employees VALUES
  ('John', 'Boston', 92000),
  ('Kathy', 'Boston', 85000),
  ('Amy', 'Dallas', 78000),
  ('Bob', 'Dallas', 92000);

SELECT name, city, salary,
  ROW_NUMBER() OVER (PARTITION BY city ORDER BY salary) AS 'Row Number'
FROM employees;

以下是该语句的输出:

+-------+--------+----------+------------+
| name  | city   | salary   | Row Number |
+-------+--------+----------+------------+
| Kathy | Boston | 85000.00 |          1 |
| John  | Boston | 92000.00 |          2 |
| Amy   | Dallas | 78000.00 |          1 |
| Bob   | Dallas | 92000.00 |          2 |
+-------+--------+----------+------------+

根据城市和每 20000 美元一个薪资级别分区,并在每个分区内按薪资升序编号。

结合 RANK() 函数生成报表

ROW_NUMBER() 常与其他窗口函数结合使用生成报表。

DROP TABLE IF EXISTS sales;
CREATE TABLE sales (product VARCHAR(20), amount INT);
INSERT INTO sales VALUES
  ('Beverage', 2500), ('Bread', 3000), ('Beverage', 2800),
  ('Cereal', 1200), ('Bread', 2200), ('Cereal', 2000);

SELECT product, amount,
  ROW_NUMBER() OVER (ORDER BY amount DESC) AS 'Row Number',
  RANK() OVER (ORDER BY amount DESC) AS 'Rank'
FROM sales
GROUP BY product, amount
ORDER BY amount DESC;

以下是该语句的输出:

+----------+--------+------------+------+
| product  | amount | Row Number | Rank |
+----------+--------+------------+------+
| Bread    |   3000 |          1 |    1 |
| Beverage |   2800 |          2 |    2 |
| Beverage |   2500 |          3 |    3 |
| Bread    |   2200 |          4 |    4 |
| Cereal   |   2000 |          5 |    5 |
| Cereal   |   1200 |          6 |    6 |
+----------+--------+------------+------+

该查询为每个产品和销量组合编号,并计算出排名。

相关函数

以下是几个与 MariaDB ROW_NUMBER() 相关的函数:

  • MariaDB RANK() 函数为分区内的行分配排名,并处理并列情况
  • MariaDB DENSE_RANK() 函数为分区内的行分配连续排名
  • MariaDB NTILE() 函数用于将分区内的行分配到若干个组

结论

MariaDB ROW_NUMBER() 是一个十分实用的窗口函数。它能够为查询结果集中的每一行分配一个连续的行号,行号的计算基于指定的分区和排序条件。结合其他窗口函数,可以方便地生成排名报表和其他分析型查询结果。在需要为结果集分配序号或生成分页数据的场景下,ROW_NUMBER() 会是个非常好的选择。当然,使用时也需注意分区和排序条件的选择,确保结果符合预期。总的来说,ROW_NUMBER() 是一个非常有用且高效的行号分配函数。