假设有一个业务场景,要查找一个订单关联的所有流转单,并且只要其中每一个流转单关联信息的最新数据,那么使用这个窗口函数可以将原来的一个一对多对多的查询变成一对多对一的查询。
LEFT JOIN (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY work_circulation_id ORDER BY create_time DESC) AS rn
FROM
feedback
) f ON f.work_circulation_id = wc.id AND f.rn = 1
`ROW_NUMBER() OVER` 是 SQL 中一个非常有用的窗口函数,主要用于为查询结果集中的每一行分配一个唯一的序号。这个序号是从 1 开始,并且是根据指定的排序规则递增的。窗口函数的强大之处就在于它能够在不改变结果集的前提下,对每一行进行计算和处理。
语法
`ROW_NUMBER()` 的基本语法如下:
sql
ROW_NUMBER() OVER (
[PARTITION BY partition_column1, partition_column2, ... ]
ORDER BY sort_column1 [ASC|DESC], sort_column2 [ASC|DESC], ...
)
参数说明
1. **PARTITION BY**:
- 可选项,用于将结果集划分为多个分区。`ROW_NUMBER()` 会在每个分区内部重新开始编号。比如,如果按某个列(如 `部门`)进行分区,则每个部门的行号都会从 1 开始。
- 如果没有指定 `PARTITION BY`,则认为整个结果集是一个单一的分区。
2. **ORDER BY**:
- 这是必须的,它决定了如何对结果集进行排序,以便为每一行分配一个行号。可以根据一个或多个列进行排序,且可以指定升序(`ASC`)或降序(`DESC`)排序。
示例
假设有以下的员工表 `employees`:
| id | name | department | salary |
|----|---------|------------|---------|
| 1 | John | Sales | 5000 |
| 2 | Jane | Sales | 6000 |
| 3 | Tom | HR | 4500 |
| 4 | Anna | HR | 7000 |
| 5 | Bob | IT | 5500 |
如果我们想要为每个部门的员工按薪水进行编号,可以使用如下 SQL 语句:
sql
SELECT
id,
name,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM
employees;
查询结果
执行上述查询后,我们会得到如下结果:
| id | name | department | salary | row_num |
|----|------|------------|--------|---------|
| 2 | Jane | Sales | 6000 | 1 |
| 1 | John | Sales | 5000 | 2 |
| 4 | Anna | HR | 7000 | 1 |
| 3 | Tom | HR | 4500 | 2 |
| 5 | Bob | IT | 5500 | 1 |
解释
- 在上面的结果中,`row_num` 列显示了每个部门内部的员工根据薪水排序后的行号。
- 对于 `Sales` 部门,`Jane` 因为薪水最高被标记为 1,`John` 被标记为 2;而在 `HR` 部门,`Anna` 被标记为 1,`Tom` 被标记为 2。
`ROW_NUMBER() OVER` 函数在数据分析和报告生成中非常有用,特别是在需要对数据进行分组和排序的场景下。它不仅允许用户对结果集中的行进行编号,还能根据特定条件分组,这为后续的数据处理和分析提供了极大的便利。