文档首页
MySQL 8.4 参考手册
8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

MySQL 8.4 参考手册 / 14 函数和运算符 / 14.20 窗口函数 / 14.20.2 窗口函数概念和语法
中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

14.20.2 窗口函数的概念和语法14.20.2 Window Function Concepts and Syntax

本节描述了如何使用窗口函数。示例使用与在GROUPING()函数的讨论中相同的销售信息数据集,参见第 14.19.2 节,“GROUP BY 修饰符”:This section describes how to use window functions. Examples use the same sales information data set as found in the discussion of the GROUPING() function in Section 14.19.2, “GROUP BY Modifiers”:

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 |
+---------+----------------+

相比之下,窗口操作不会将查询行的组折叠成单个输出行。相反,它们会为每一行生成一个结果。像前面的查询一样,下面的查询使用了SUM(),但这一次作为窗口函数: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:

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 |
+------+---------+------------+--------+--------------+----------------+

查询中的每个窗口操作都通过包含一个OVER子句来表示,该子句指定如何将查询行划分为组,以便由窗口函数处理:Each window operation in the query is signified by inclusion of an 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. The window function thus produces a global sum, but does so for each row.

  • 第二个OVER子句按国家划分行,为每个分区(每个国家)生成一个总和。函数为每个分区行生成这个总和。The second OVER clause partitions rows by country, producing a sum per partition (per country). The function produces this sum for each partition row.

窗口函数仅允许在选择列表和ORDER BY子句中使用。查询结果行是从FROM子句确定的,在WHERE、GROUP BY和HAVING处理之后,而窗口函数的执行发生在ORDER BY、LIMIT和SELECT DISTINCT之前。Window functions are permitted only in the select list and ORDER BY clause. 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.

OVER子句允许用于许多聚合函数,因此这些函数可以作为窗口函数或非窗口函数使用,这取决于是否存在OVER子句: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:

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()

有关每个聚合函数的详细信息,请参阅第 14.19.1 节,“聚合函数说明”。For details about each aggregate function, see Section 14.19.1, “Aggregate Function Descriptions”.

MySQL 还支持仅作为窗口函数使用的非聚合函数。对于这些函数,OVER 子句是必需的:MySQL also supports nonaggregate functions that are used only as window functions. For these, the OVER clause is mandatory:

CUME_DIST()
DENSE_RANK()
FIRST_VALUE()
LAG()
LAST_VALUE()
LEAD()
NTH_VALUE()
NTILE()
PERCENT_RANK()
RANK()
ROW_NUMBER()

有关每个非聚合函数的详细信息,请参见 第 14.20.1 节,“窗口函数描述”。For details about each nonaggregate function, see Section 14.20.1, “Window Function Descriptions”.

作为这些非聚合窗口函数之一的示例,此查询使用了 ROW_NUMBER(),它生成每个分区内每行的行号。在此情况下,每个国家的行都会被编号。默认情况下,分区行是无序的,行号是非确定性的。要对分区行进行排序,请在窗口定义中包含 ORDER BY 子句。该查询使用无序和有序分区(row_num1 和 row_num2 列)来说明省略和包含 ORDER BY 的区别: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. 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. The query uses unordered and ordered partitions (the row_num1 and row_num2 columns) to illustrate the difference between omitting and including 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 |
+------+---------+------------+--------+----------+----------+

如前所述,要使用窗口函数(或将聚合函数视为窗口函数),需在函数调用后包含一个 OVER 子句。OVER 子句有两种形式: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. The OVER clause has two forms:

over_clause:
    {OVER (window_spec) | OVER window_name}

这两种形式都定义了窗口函数应如何处理查询行。它们的不同之处在于窗口是直接在 OVER 子句中定义,还是通过引用查询中其他地方定义的命名窗口提供: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.

  • 在第二种情况下,window_name 是由查询中其他地方的 WINDOW 子句定义的窗口规范的名称。有关详细信息,请参见 第 14.20.4 节,“命名窗口”。In the second case, window_name is the name for a window specification defined by a WINDOW clause elsewhere in the query. For details, see Section 14.20.4, “Named Windows”.

对于 OVER (window_spec) 语法,窗口规范有几个部分,都是可选的:For OVER (window_spec) syntax, the window specification has several parts, all optional:

window_spec:
    [window_name] [partition_clause] [order_clause] [frame_clause]

如果 OVER() 为空,窗口包括所有查询行,窗口函数使用所有行计算结果。否则,圆括号内的子句决定使用哪些查询行来计算函数结果,以及它们如何进行分区和排序:If OVER() is empty, the window consists of all query rows and the window function computes a result using all rows. 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:由查询中其他地方的 WINDOW 子句定义的窗口名称。如果 window_name 独立出现在 OVER 子句中,则完全定义该窗口。如果还提供了分区、排序或帧子句,则它们会修改对命名窗口的解释。详情请参阅 第 14.20.4 节,“命名窗口”。window_name: The name of a window defined by a WINDOW clause elsewhere in the query. If window_name appears by itself within the OVER clause, it completely defines the window. If partitioning, ordering, or framing clauses are also given, they modify interpretation of the named window. For details, see Section 14.20.4, “Named Windows”.

  • partition_clause:PARTITION BY 子句指示如何将查询行划分为多个组。给定行的窗口函数结果基于包含该行的分区的行。如果省略 PARTITION BY,则只有一个包含所有查询行的分区。partition_clause: A PARTITION BY clause indicates how to divide the query rows into groups. 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.

    Note

    窗口函数的分区与表分区不同。有关表分区的信息,请参见 第 26 章,分区。Partitioning for window functions differs from table partitioning. For information about table partitioning, see Chapter 26, Partitioning.

    partition_clause 的语法如下:partition_clause has this syntax:

    partition_clause:
        PARTITION BY expr [, expr] ...
    

    标准 SQL 要求 PARTITION BY 后面只能跟列名。MySQL 的一个扩展是允许表达式,而不仅仅是列名。例如,如果一张表包含名为 ts 的 TIMESTAMP 列,标准 SQL 允许 PARTITION BY ts,但不允许 PARTITION BY HOUR(ts),而 MySQL 两者都允许。Standard SQL requires PARTITION BY to be followed by column names only. A MySQL extension is to permit expressions, not just column names. 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.

  • order_clause:ORDER BY 子句指示如何对每个分区中的行进行排序。根据 ORDER BY 子句相等的分区行被视为同行。如果省略 ORDER BY,分区行是无序的,没有指定的处理顺序,并且所有分区行都是同行。order_clause: An ORDER BY clause indicates how to sort rows in each partition. Partition rows that are equal according to the ORDER BY clause are considered peers. If ORDER BY is omitted, partition rows are unordered, with no processing order implied, and all partition rows are peers.

    order_clause 的语法如下:order_clause has this syntax:

    order_clause:
        ORDER BY expr [ASC|DESC] [, expr [ASC|DESC]] ...
    

    每个 ORDER BY 表达式后面可以可选地跟 ASC 或 DESC 来指示排序方向。如果未指定方向,默认是 ASC。NULL 值在升序排序时排在最前,在降序排序时排在最后。Each ORDER BY expression optionally can be followed by ASC or DESC to indicate sort direction. The default is ASC if no direction is specified. NULL values sort first for ascending sorts, last for descending sorts.

    窗口定义中的 ORDER BY 仅在各个分区内应用。要对整个结果集进行排序,请在查询顶层包含 ORDER BY。An ORDER BY in a window definition applies within individual partitions. To sort the result set as a whole, include an ORDER BY at the query top level.

  • frame_clause:帧是当前分区的一个子集,帧子句指定如何定义该子集。帧子句还有许多自己的子子句。详细信息请参见 第 14.20.3 节,“窗口函数帧规范”。frame_clause: A frame is a subset of the current partition and the frame clause specifies how to define the subset. The frame clause has many subclauses of its own. For details, see Section 14.20.3, “Window Function Frame Specification”.