This section describes how to use window functions. 本节介绍如何使用窗口函数。Examples use the same sales information data set as found in the discussion of the 示例使用与第12.20.2节,“GROUP BY修饰符”中GROUPING()
function in Section 12.20.2, “GROUP BY Modifiers”:GROUPING()
函数讨论中相同的销售信息数据集:
mysql> SELECT * FROM sales ORDER BY country, year, product;
+------+---------+------------+--------+
| year | country | product | profit |
+------+---------+------------+--------+
| 2000 | Finland | Computer | 1500 |
| 2000 | Finland | Phone | 100 |
| 2001 | Finland | Phone | 10 |
| 2000 | India | Calculator | 75 |
| 2000 | India | Calculator | 75 |
| 2000 | India | Computer | 1200 |
| 2000 | USA | Calculator | 75 |
| 2000 | USA | Computer | 1500 |
| 2001 | USA | Calculator | 50 |
| 2001 | USA | Computer | 1500 |
| 2001 | USA | Computer | 1200 |
| 2001 | USA | TV | 150 |
| 2001 | USA | TV | 100 |
+------+---------+------------+--------+
A window function performs an aggregate-like operation on a set of query rows. 窗口函数对一组查询行执行类似聚合的操作。However, whereas an aggregate operation groups query rows into a single result row, a window function produces a result for each query row:但是,聚合操作将查询行分组为单个结果行,而窗口函数则为每个查询行生成一个结果:
The row for which function evaluation occurs is called the current row.对其进行函数求值的行称为当前行。
The query rows related to the current row over which function evaluation occurs comprise the window for the current row.与发生函数求值的当前行相关的查询行构成当前行的窗口。
For example, using the sales information table, these two queries perform aggregate operations that produce a single global sum for all rows taken as a group, and sums grouped per country:例如,使用销售信息表,这两个查询执行聚合操作,为作为一个组的所有行和按国家/地区分组的总和生成一个全局总和:
mysql>SELECT SUM(profit) AS total_profit
FROM sales;
+--------------+ | total_profit | +--------------+ | 7535 | +--------------+ mysql>SELECT country, SUM(profit) AS country_profit
FROM sales
GROUP BY country
ORDER BY country;
+---------+----------------+ | country | country_profit | +---------+----------------+ | Finland | 1610 | | India | 1350 | | USA | 4575 | +---------+----------------+
By contrast, window operations do not collapse groups of query rows to a single output row. 相反,窗口操作不会将查询行组折叠为单个输出行。Instead, they produce a result for each row. 相反,它们为每一行生成一个结果。Like the preceding queries, the following query uses 与前面的查询一样,下面的查询使用SUM()
, but this time as a window function:SUM()
,但这次使用的是窗口函数:
mysql>SELECT
year, country, product, profit,
SUM(profit) OVER() AS total_profit,
SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;
+------+---------+------------+--------+--------------+----------------+ | year | country | product | profit | total_profit | country_profit | +------+---------+------------+--------+--------------+----------------+ | 2000 | Finland | Computer | 1500 | 7535 | 1610 | | 2000 | Finland | Phone | 100 | 7535 | 1610 | | 2001 | Finland | Phone | 10 | 7535 | 1610 | | 2000 | India | Calculator | 75 | 7535 | 1350 | | 2000 | India | Calculator | 75 | 7535 | 1350 | | 2000 | India | Computer | 1200 | 7535 | 1350 | | 2000 | USA | Calculator | 75 | 7535 | 4575 | | 2000 | USA | Computer | 1500 | 7535 | 4575 | | 2001 | USA | Calculator | 50 | 7535 | 4575 | | 2001 | USA | Computer | 1200 | 7535 | 4575 | | 2001 | USA | Computer | 1500 | 7535 | 4575 | | 2001 | USA | TV | 100 | 7535 | 4575 | | 2001 | USA | TV | 150 | 7535 | 4575 | +------+---------+------------+--------+--------------+----------------+
Each window operation in the query is signified by inclusion of an 查询中的每个窗口操作都通过包含OVER子句来表示,OVER
clause that specifies how to partition query rows into groups for processing by the window function:OVER
子句指定如何将查询行划分为组以供窗口函数处理:
The first 第一个OVER
clause is empty, which treats the entire set of query rows as a single partition. OVER
子句为空,它将整个查询行集视为单个分区。The window function thus produces a global sum, but does so for each row.因此,窗口函数生成一个全局和,但对每一行都这样做。
The second 第二个OVER
clause partitions rows by country, producing a sum per partition (per country). OVER
子句按国家对行进行分区,生成每个分区(每个国家)的总和。The function produces this sum for each partition row.函数为每个分区行生成这个和。
Window functions are permitted only in the select list and 窗口函数只允许在ORDER BY
clause. SELECT
列表和ORDER BY
子句中使用。Query result rows are determined from the 查询结果行由FROM
clause, after WHERE
, GROUP BY
, and HAVING
processing, and windowing execution occurs before ORDER BY
, LIMIT
, and SELECT DISTINCT
.FROM
子句确定,在WHERE
、GROUP BY
和HAVING
处理之后,窗口执行在ORDER BY
、LIMIT
和SELECT DISTINCT
之前发生。
The OVER
clause is permitted for many aggregate functions, which therefore can be used as window or nonwindow functions, depending on whether the OVER
clause is present or absent:OVER
子句允许用于许多聚合函数,因此可以用作窗口函数或非窗口函数,具体取决于OVER
子句是否存在:
AVG() BIT_AND() BIT_OR() BIT_XOR() COUNT() JSON_ARRAYAGG() JSON_OBJECTAGG() MAX() MIN() STDDEV_POP(), STDDEV(), STD() STDDEV_SAMP() SUM() VAR_POP(), VARIANCE() VAR_SAMP()
For details about each aggregate function, see Section 12.20.1, “Aggregate Function Descriptions”.有关每个聚合函数的详细信息,请参阅第12.20.1节,“聚合函数描述”。
MySQL also supports nonaggregate functions that are used only as window functions. MySQL还支持仅用作窗口函数的非聚集函数。For these, the 对于这些,OVER
clause is mandatory:OVER
子句是强制性的:
CUME_DIST() DENSE_RANK() FIRST_VALUE() LAG() LAST_VALUE() LEAD() NTH_VALUE() NTILE() PERCENT_RANK() RANK() ROW_NUMBER()
For details about each nonaggregate function, see Section 12.21.1, “Window Function Descriptions”.有关每个非聚集函数的详细信息,请参阅第12.21.1节,“窗口函数描述”。
As an example of one of those nonaggregate window functions, this query uses 作为这些非聚集窗口函数之一的示例,此查询使用ROW_NUMBER()
, which produces the row number of each row within its partition. ROW_NUMBER()
,它生成其分区中每一行的行号。In this case, rows are numbered per country. 在本例中,行是按国家编号的。By default, partition rows are unordered and row numbering is nondeterministic. 默认情况下,分区行是无序的,行编号是不确定的。To sort partition rows, include an 要对分区行进行排序,请在窗口定义中包含ORDER BY
clause within the window definition. ORDER BY
子句。The query uses unordered and ordered partitions (the 查询使用无序分区和有序分区(row_num1
and row_num2
columns) to illustrate the difference between omitting and including ORDER BY
:row_num1
和row_num2
列)来说明省略和包含ORDER BY
的区别:
mysql>SELECT
year, country, product, profit,
ROW_NUMBER() OVER(PARTITION BY country) AS row_num1,
ROW_NUMBER() OVER(PARTITION BY country ORDER BY year, product) AS row_num2
FROM sales;
+------+---------+------------+--------+----------+----------+ | year | country | product | profit | row_num1 | row_num2 | +------+---------+------------+--------+----------+----------+ | 2000 | Finland | Computer | 1500 | 2 | 1 | | 2000 | Finland | Phone | 100 | 1 | 2 | | 2001 | Finland | Phone | 10 | 3 | 3 | | 2000 | India | Calculator | 75 | 2 | 1 | | 2000 | India | Calculator | 75 | 3 | 2 | | 2000 | India | Computer | 1200 | 1 | 3 | | 2000 | USA | Calculator | 75 | 5 | 1 | | 2000 | USA | Computer | 1500 | 4 | 2 | | 2001 | USA | Calculator | 50 | 2 | 3 | | 2001 | USA | Computer | 1500 | 3 | 4 | | 2001 | USA | Computer | 1200 | 7 | 5 | | 2001 | USA | TV | 150 | 1 | 6 | | 2001 | USA | TV | 100 | 6 | 7 | +------+---------+------------+--------+----------+----------+
As mentioned previously, to use a window function (or treat an aggregate function as a window function), include an 如前所述,要使用窗口函数(或将聚合函数视为窗口函数),请在函数调用后包含OVER
clause following the function call. OVER
子句。The OVER
clause has two forms:OVER
子句有两种形式:
over_clause
: {OVER (window_spec
) | OVERwindow_name
}
Both forms define how the window function should process query rows. 这两种形式都定义了窗口函数应该如何处理查询行。They differ in whether the window is defined directly in the 它们的区别在于窗口是直接在OVER
clause, or supplied by a reference to a named window defined elsewhere in the query:OVER
子句中定义的,还是通过引用查询中其他地方定义的命名窗口提供的:
In the first case, the window specification appears directly in the 在第一种情况下,窗口规范直接出现在OVER
clause, between the parentheses.OVER
子句中,位于括号之间。
In the second case, 在第二种情况下,window_name
is the name for a window specification defined by a WINDOW
clause elsewhere in the query. window_name
是由查询中其他地方的window子句定义的窗口规范的名称。For details, see Section 12.21.4, “Named Windows”.有关详细信息,请参阅第12.21.4节,“命名窗口”。
For 对于OVER (
syntax, the window specification has several parts, all optional:window_spec
)OVER (
语法,window规范有几个部分,都是可选的:window_spec
)
window_spec
: [window_name
] [partition_clause
] [order_clause
] [frame_clause
]
If 如果OVER()
is empty, the window consists of all query rows and the window function computes a result using all rows. OVER()
为空,则窗口由所有查询行组成,窗口函数使用所有行计算结果。Otherwise, the clauses present within the parentheses determine which query rows are used to compute the function result and how they are partitioned and ordered:否则,括号内的子句将确定哪些查询行用于计算函数结果,以及如何对它们进行分区和排序:
window_name
: The name of a window defined by a :由查询中其他位置的WINDOW
clause elsewhere in the query. WINDOW
子句定义的窗口的名称。If 如果window_name
appears by itself within the OVER
clause, it completely defines the window. window_name
本身出现在OVER
子句中,则它完全定义了窗口。If partitioning, ordering, or framing clauses are also given, they modify interpretation of the named window. 如果还提供了分区、排序或框架子句,则它们会修改命名窗口的解释。For details, see Section 12.21.4, “Named Windows”.有关详细信息,请参阅第12.21.4节,“命名窗口”。
partition_clause
: A :PARTITION BY
clause indicates how to divide the query rows into groups. PARTITION BY
子句指示如何将查询行划分为组。The window function result for a given row is based on the rows of the partition that contains the row. 给定行的窗口函数结果基于包含该行的分区的行。If 如果省略PARTITION BY
is omitted, there is a single partition consisting of all query rows.PARTITION BY
,则有一个由所有查询行组成的分区。
Partitioning for window functions differs from table partitioning. 窗口函数的分区不同于表分区。For information about table partitioning, see Chapter 24, Partitioning.有关表分区的信息,请参阅第24章,分区。
partition_clause
has this syntax:partition_clause
子句具有以下语法:
partition_clause
: PARTITION BYexpr
[,expr
] ...
Standard SQL requires 标准SQL要求PARTITION BY
to be followed by column names only. PARTITION BY
后面只能跟列名。A MySQL extension is to permit expressions, not just column names. MySQL扩展允许表达式,而不仅仅是列名。For example, if a table contains a 例如,如果一个表包含一个名为TIMESTAMP
column named ts
, standard SQL permits PARTITION BY ts
but not PARTITION BY HOUR(ts)
, whereas MySQL permits both.ts
的TIMESTAMP
列,那么标准SQL允许PARTITION BY ts
,但不允许PARTITION BY HOUR(ts)
,而MySQL允许这两者。
order_clause
: An :ORDER BY
clause indicates how to sort rows in each partition. ORDER BY
子句指示如何对每个分区中的行进行排序。Partition rows that are equal according to the 根据ORDER BY
clause are considered peers. ORDER BY
子句相等的分区行被认为是对等的。If 如果省略ORDER BY
is omitted, partition rows are unordered, with no processing order implied, and all partition rows are peers.ORDER BY
,则分区行是无序的,没有隐含处理顺序,并且所有分区行都是对等的。
order_clause
has this syntax:order_clause
的语法如下:
order_clause
: ORDER BYexpr
[ASC|DESC] [,expr
[ASC|DESC]] ...
Each 每个ORDER BY
expression optionally can be followed by ASC
or DESC
to indicate sort direction. ORDER BY
表达式后面可以可选地跟ASC
或DESC
,以指示排序方向。The default is 如果未指定方向,则默认为ASC
if no direction is specified. ASC
。NULL
values sort first for ascending sorts, last for descending sorts.NULL
值在升序排序中位于前面,在降序排序中位于后面。
An 窗口定义中的ORDER BY
in a window definition applies within individual partitions. ORDER BY
应用于各个分区。To sort the result set as a whole, include an 要将结果集作为一个整体进行排序,请在查询顶层包含ORDER BY
at the query top level.ORDER BY
。
frame_clause
: A frame is a subset of the current partition and the frame clause specifies how to define the subset. :框是当前分区的子集,frame_clause
指定如何定义子集。The frame clause has many subclauses of its own. frame_clause
有许多自己的子类。For details, see Section 12.21.3, “Window Function Frame Specification”.有关详细信息,请参阅第12.21.3节,“窗口函数框规范”。