MySQL窗口函数:从理论到实践

目录

1. ROW_NUMBER()

2. RANK()

3. DENSE_RANK()

4. NTILE(n)

5. LAG() 和 LEAD()

6. FIRST_VALUE() 和 LAST_VALUE()

总结


MySQL中的窗口函数(Window Functions)允许用户对一个结果集的窗口(或分区)执行计算,这些窗口是由查询的每行定义的。窗口函数在SQL标准中定义,并且在MySQL 8.0及更高版本中可用。窗口函数为每行返回一个值,这个值是基于该行在其分区或整个结果集中的位置计算得出的。

窗口函数通常与OVER()子句一起使用,OVER()子句定义了窗口的范围或边界。over()里头的分组以及排序的执行晚于外头 where 、group by、  order by 的执行。

以原始sales表数据为例,介绍一些常见的MySQL窗口函数:

product_id

sale_date

amount

1

2023-01-01

100.00

2

2023-01-02

150.00

3

2023-01-03

150.00

1

2023-01-04

120.00

2

2023-01-05

180.00

1. ROW_NUMBER()

- 为结果集中的每一行分配一个唯一的序号。

SELECT 
    product_id, 
    sale_date, 
    amount, 
    ROW_NUMBER() OVER (ORDER BY sale_date) AS row_num 
FROM sales;

查询结果

product_id

sale_date

amount

row_num

1

2023-01-01

100.00

1

2

2023-01-02

150.00

2

3

2023-01-03

150.00

3

1

2023-01-04

120.00

4

2

2023-01-05

180.00

5

2. RANK()

- 为结果集中的每一行分配一个唯一的排名,对于平级记录会留下空位。例如,如果有两行并列第一,则它们都会被分配排名1,下一行将被分配排名3(而不是2)。

SELECT 
    product_id, 
    sale_date, 
    amount, 
    RANK() OVER (ORDER BY amount DESC) AS rank 
FROM sales;

查询结果

product_id

sale_date

amount

rank

2

2023-01-05

180.00

1

2

2023-01-02

150.00

2

3

2023-01-03

150.00

2

1

2023-01-04

120.00

4

1

2023-01-01

100.00

5

3. DENSE_RANK()

- 类似于RANK(),但不会留下空位。

SELECT 
    product_id, 
    sale_date, 
    amount, 
    DENSE_RANK() OVER (ORDER BY amount DESC) AS dense_rank 
FROM sales;

查询结果

product_id

sale_date

amount

dense_rank

2

2023-01-05

180.00

1

2

2023-01-02

150.00

2

3

2023-01-03

150.00

2

1

2023-01-04

120.00

3

1

2023-01-01

100.00

4

4. NTILE(n)

- 将结果集分为“n”个大致相等的部分,并为每行分配一个桶号。

SELECT 
    product_id, 
    sale_date, 
    amount, 
    NTILE(2) OVER (ORDER BY sale_date) AS quarter 
FROM sales;

查询结果

product_id

sale_date

amount

quarter

1

2023-01-01

100.00

1

2

2023-01-02

150.00

1

3

2023-01-03

150.00

2

1

2023-01-04

120.00

2

2

2023-01-05

180.00

2

5. LAG() 和 LEAD()

- 允许访问前面或后面的行而无需自连接。

SELECT 
product_id, 
sale_date, 
amount, 
LAG(amount) OVER (PARTITION BY product_id ORDER BY sale_date) AS previous_amount 
FROM sales;

查询结果

product_id

sale_date

amount

previous_amount

1

2023-01-01

100.00

NULL

2

2023-01-02

150.00

NULL

3

2023-01-03

150.00

NULL

1

2023-01-04

120.00

100.00

2

2023-01-05

180.00

150.00

6. FIRST_VALUE() 和 LAST_VALUE()

- 返回窗口内的第一个或最后一个值。

SELECT 
product_id, 
sale_date, 
amount, 
FIRST_VALUE(amount) OVER (PARTITION BY product_id ORDER BY sale_date) AS first_amount 
FROM sales;

查询结果

product_id

sale_date

amount

first_amount

1

2023-01-01

100.00

100.00

2

2023-01-02

150.00

150.00

3

2023-01-03

150.00

150.00

1

2023-01-04

120.00

100.00

2

2023-01-05

180.00

150.00

请注意,OVER()子句可以包含PARTITION BY来定义窗口内的分区,每个分区都独立地应用窗口函数。

SELECT 
product_id, 
sale_date, 
amount, 
SUM(amount) OVER (PARTITION BY product_id) AS total_amount_per_product 
FROM sales;

在这个例子中,SUM(amount)函数在每个product_id分区内独立计算。

查询结果

product_id

sale_date

amount

total_amount_per_product

1

2023-01-01

100.00

220.00

2

2023-01-02

150.00

330.00

3

2023-01-03

150.00

150.00

1

2023-01-04

120.00

220.00

2

2023-01-05

180.00

330.00

总结

窗口函数在处理涉及多个行但不需要进行复杂分组或连接的问题时非常有用,比如计算运行总计、排名或查找前一行/后一行的值等。

你可能感兴趣的:(数据库,mysql,数据库)