分析函数,也称为窗口函数,是一种在 SQL 查询中对数据集中的行进行复杂计算的函数。窗口函数的特点在于,它们不会减少查询结果的行数,而是为每一行增加一个新的计算结果。窗口函数适用于多种分析场景,如计算滚动合计、排名以及移动平均等。
下面是一个使用窗口函数计算每个商店的前后三天的销售移动平均值的例子:
CREATE TABLE daily_sales
(store_id INT, sales_date DATE, sales_amount DECIMAL(10, 2))
PROPERTIES (
"replication_num" = "1"
);
INSERT INTO daily_sales (store_id, sales_date, sales_amount) VALUES (1, '2023-01-01', 100.00), (1, '2023-01-02', 150.00), (1, '2023-01-03', 200.00), (1, '2023-01-04', 250.00), (1, '2023-01-05', 300.00), (1, '2023-01-06', 350.00), (1, '2023-01-07', 400.00), (1, '2023-01-08', 450.00), (1, '2023-01-09', 500.00), (2, '2023-01-01', 110.00), (2, '2023-01-02', 160.00), (2, '2023-01-03', 210.00), (2, '2023-01-04', 260.00), (2, '2023-01-05', 310.00), (2, '2023-01-06', 360.00), (2, '2023-01-07', 410.00), (2, '2023-01-08', 460.00), (2, '2023-01-09', 510.00);
SELECT
store_id,
sales_date,
sales_amount,
AVG(sales_amount) OVER ( PARTITION BY store_id ORDER BY sales_date
ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING ) AS moving_avg_sales
FROM
daily_sales;
查询结果为如下:
+----------+------------+--------------+------------------+
| store_id | sales_date | sales_amount | moving_avg_sales |
+----------+------------+--------------+------------------+
| 1 | 2023-01-01 | 100.00 | 175.0000 |
| 1 | 2023-01-02 | 150.00 | 200.0000 |
| 1 | 2023-01-03 | 200.00 | 225.0000 |
| 1 | 2023-01-04 | 250.00 | 250.0000 |
| 1 | 2023-01-05 | 300.00 | 300.0000 |
| 1 | 2023-01-06 | 350.00 | 350.0000 |
| 1 | 2023-01-07 | 400.00 | 375.0000 |
| 1 | 2023-01-08 | 450.00 | 400.0000 |
| 1 | 2023-01-09 | 500.00 | 425.0000 |
| 2 | 2023-01-01 | 110.00 | 185.0000 |
| 2 | 2023-01-02 | 160.00 | 210.0000 |
| 2 | 2023-01-03 | 210.00 | 235.0000 |
| 2 | 2023-01-04 | 260.00 | 260.0000 |
| 2 | 2023-01-05 | 310.00 | 310.0000 |
| 2 | 2023-01-06 | 360.00 | 360.0000 |
| 2 | 2023-01-07 | 410.00 | 385.0000 |
| 2 | 2023-01-08 | 460.00 | 410.0000 |
| 2 | 2023-01-09 | 510.00 | 435.0000 |
+----------+------------+--------------+------------------+
18 rows in set (0.09 sec)
基本概念介绍
处理顺序
使用分析函数的查询处理可以分为三个阶段。
-
执行所有的连接、WHERE、GROUP BY 和 HAVING 子句。
-
将结果集提供给分析函数,并进行所有必要的计算。
-
如果查询的末尾包含 ORDER BY 子句,则处理该子句以实现精确的输出排序。
查询的处理顺序如图所示:
结果集分区
分区是在使用 PARTITION BY 子句定义的组之后创建的。分析函数允许用户将查询结果集划分为称为分区的行组。
注意
分析函数中使用的术语“分区”与表分区功能无关。在本章中,术语“分区”仅指与分析函数相关的含义。
窗口
对于分区中的每一行,你可以定义一个滑动数据窗口。此窗口确定了用于执行当前行计算所涉及的行范围。窗口具有一个起始行和一个结束行,根据其定义,窗口可以在一端或两端进行滑动。例如,为累积和函数定义的窗口,其起始行固定在其分区的第一行,而其结束行则从起点一直滑动到分区的最后一行。相反,为移动平均值定义的窗口,其起点和终点都会进行滑动。
窗口的大小可以设置为与分区中的所有行一样大,也可以设置为在分区内仅包含一行的滑动窗口。需要注意的是,当窗口靠近分区的边界时,由于边界的限制,计算的范围可能会缩减行数,此时函数仅返回可用行的计算结果。
在使用窗口函数时,当前行会被包含在计算之中。因此,在处理 n 个项目时,应指定为 (n-1)。例如,如果您需要计算五天的平均值,窗口应指定为“rows between 4 preceding and current row”,这也可以简写为“rows 4 preceding”。
当前行
使用分析函数执行的每个计算都是基于分区内的当前行。当前行作为确定窗口开始和结束的参考点,具体如图所示。
例如,可以使用一个窗口来定义中心移动平均值计算,该窗口包含当前行、当前行之前的 6 行以及当前行之后的 6 行。这样就创建了一个包含 13 行的滑动窗口。
排序函数
排序函数中,只有当指定的排序列是唯一值列时,查询结果才是确定的;如果排序列包含重复值,则每次的查询结果可能不同。
NTILE 函数
NTILE 是 SQL 中的一种窗口函数,用于将查询结果集分成指定数量的桶(组),并为每一行分配一个桶号。这在数据分析和报告中非常有用,特别是在需要对数据进行分组和排序时。
1. 函数语法
NTILE(num_buckets) OVER ([PARTITION BY partition_expression] ORDER BY order_expression)
-
num_buckets
:要将行划分成的桶的数量。 -
PARTITION BY partition_expression
(可选):定义如何分区数据。 -
O