MySQL 8.0开始引入了开窗函数,使得SQL语句能够以更复杂的方式操作数据集。

06-14 1536阅读

在MySQL中使用`ROW_NUMBER()`函数时,可以通过一个简单的图表来帮助理解它是如何工作的。以下是对`ROW_NUMBER()`函数的图解说明:

MySQL 8.0开始引入了开窗函数,使得SQL语句能够以更复杂的方式操作数据集。
(图片来源网络,侵删)

假设我们有一个名为`employees`的表,其中包含以下列:`employee_id`(员工ID),`first_name`(名),`last_name`(姓),和`hire_date`(入职日期)。表中的数据如下:

| employee_id | first_name | last_name | hire_date   |

|-------------|------------|-----------|--------------|

| 1           | John       | Doe      | 2018-06-01   |

| 2           | Jane       | Smith    | 2018-06-02   |

| 3           | Bob        | Johnson  | 2018-06-01   |

| 4           | Alice      | Davis    | 2018-06-03   |

| 5           | Mike       | Brown    | 2018-06-04   |

现在我们使用`ROW_NUMBER()`函数来为每个员工基于`hire_date`字段分配一个序号:

```sql

SELECT 

  employee_id,

  first_name,

  last_name,

  hire_date,

  ROW_NUMBER() OVER (ORDER BY hire_date) AS row_num

FROM 

  employees;

```

执行上述查询后,结果集可能会如下所示:

| employee_id | first_name | last_name | hire_date   | row_num |

|-------------|------------|-----------|--------------|---------|

| 1           | John       | Doe      | 2018-06-01   | 1       |

| 3           | Bob        | Johnson  | 2018-06-01   | 1       |

| 2           | Jane       | Smith    | 2018-06-02   | 2       |

| 4           | Alice      | Davis    | 2018-06-03   | 3       |

| 5           | Mike       | Brown    | 2018-06-04   | 4       |

**图解**:

1. 首先,`ROW_NUMBER()`函数在结果集上应用,根据`hire_date`字段对员工进行排序。

2. 然后,它为排序后的结果集中的每一行分配一个唯一的序号,序号从1开始。

3. 如果有多个员工在同一个日期入职(如员工1和员工3),`ROW_NUMBER()`仍然为它们分配连续的序号,而不是跳过。

图表表示可能如下:

```

+-------------+------------+-----------+--------------+--------+

| employee_id | first_name | last_name | hire_date   | row_num|

+-------------+------------+-----------+--------------+--------+

| 1           | John       | Doe      | 2018-06-01   |   1    |

| 3           | Bob        | Johnson  | 2018-06-01   |   1    |

| 2           | Jane       | Smith    | 2018-06-02   |   2    |

| 4           | Alice      | Davis    | 2018-06-03   |   3    |

| 5           | Mike       | Brown    | 2018-06-04   |   4    |

+-------------+------------+-----------+--------------+--------+

   排序依据 ->  ^ 

   序号       ->  1, 1, 2, 3, 4

```

在这个图表中,我们可以看到`ROW_NUMBER()`函数如何基于排序依据(`hire_date`)为每行分配序号。这个序号是连续的,即使有多行具有相同的排序值。

MySQL中的`ROW_NUMBER()`是一个开窗函数,它为结果集中的每一行分配一个唯一的序号(从1开始),这些序号的分配顺序是根据`OVER()`子句中定义的排序规则来确定的。如果存在排序相同的行,`ROW_NUMBER()`会为这些行分配连续的序号,不会跳过任何序号。

### 语法:

```sql

ROW_NUMBER() OVER (

  [PARTITION BY partition_expression, ... ]

  ORDER BY sort_expression [ASC | DESC], ...

)

```

- `PARTITION BY`:可选子句,用于指定一个或多个列,以将数据分成不同的分区。在每个分区内,`ROW_NUMBER()`会独立地为行分配序号。

- `ORDER BY`:必须子句,用于指定排序的列和顺序(升序`ASC`或降序`DESC`)。如果没有指定排序顺序,默认为升序。

### 应用场景:

- 数据去重:当需要从结果集中去除重复行时。

- 分页查询:与`LIMIT`子句结合使用,实现分页效果。

- 行排序:为数据集的行分配一个唯一的序号,以便于排序。

### 示例:

假设有一个名为`employees`的表,包含员工ID(`employee_id`)、姓名(`full_name`)和入职日期(`hire_date`),我们想要为每个员工分配一个基于入职日期的序号。

```sql

SELECT 

  employee_id,

  full_name,

  hire_date,

  ROW_NUMBER() OVER (ORDER BY hire_date) AS row_num

FROM 

  employees;

```

这个查询将返回所有员工的信息,并为每个员工根据`hire_date`的升序分配一个唯一的序号。

如果我们想要在每个部门内为员工分配序号,可以添加`PARTITION BY`子句:

```sql

SELECT 

  employee_id,

  full_name,

  department_id,

  hire_date,

  ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY hire_date) AS row_num

FROM 

  employees;

```

在这个查询中,`ROW_NUMBER()`将在每个部门内独立地为员工分配序号,基于他们的入职日期。

### 分页查询示例:

如果你想要实现分页查询,可以使用`ROW_NUMBER()`结合`LIMIT`和变量来实现。假设你想要获取第2页的数据,每页显示10条记录:

```sql

SET @row_num = 0;

SELECT 

  employee_id,

  full_name,

  hire_date

FROM 

  employees

WHERE 

  @row_num := @row_num + 1

ORDER BY 

  hire_date,

  @row_num

LIMIT 10 OFFSET 10;

```

这个查询首先设置了一个会话变量`@row_num`,然后在`WHERE`子句中使用`@row_num`来实现序号的计数,最后使用`LIMIT`和`OFFSET`来获取第2页的数据。

`ROW_NUMBER()`是一个非常有用的开窗函数,它为数据集的行提供了一个清晰的编号机制,这在许多数据分析场景中都非常有用。

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]