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() 是一个非常有用且高效的行号分配函数。