MySQL窗口函数概念和语法

原文地址:https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html

译文:

12.21.2 Window Function Concepts and Syntax

本节讲述如何使用窗口函数。示例使用的销售信息数据集与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 |
    +------+---------+------------+--------+

窗口函数对一组查询行执行类似于聚合函数的操作。但是,聚合函数是将查询行聚合到单个结果行中,而窗口函数为每个查询行生成一个结果:

    1)出现函数求值的行称为当前行;

    2)与函数求值所在的当前行相关的查询行构成当前行的窗口。

例如,使用销售信息表sales,下面两个查询执行聚合操作,为作为一组的所有行生成单个全局和,并基于国家进行分组求和:

  • 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(),但这次是作为窗口函数:

  • 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语句来表示,该语句指定如何将查询行划分为组以供窗口函数处理:

    1)第一个OVER子句是空的,它将整个查询行集视为单个分区。窗口函数因此产生一个全局和,但是对每一行都是这样;

    2)第二个OVER子句按国家划分行,生成每个分区(每个国家)的和。这个函数为分区中的每一行都生成这个和。

窗口函数只允许在select 列表和ORDER BY语句中使用。查询结果行是由from语句确定的,窗口函数在WHERE、GROUP BY和HAVING 处理之后,在ORDER BY、LIMIT和SELECT DISTINCT之前执行。

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

有关每个聚合函数的详细信息,可以参考Section 12.20.1, “Aggregate (GROUP BY) Function Descriptions”。

MySQL还支持只作为窗口函数使用的非聚合函数。对于这些函数,OVER语句是强制性的:

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

有关每个非聚合窗口函数的详细信息,可以参考Section 12.21.1, “Window Function Descriptions”。

作为这些非聚合窗口函数之一的一个示例,下面的查询使用ROW_NUMBER(),它生成分区中每一行的行号。在这种情况下,行是按国家编号的。默认情况下,分区行是无序的,行编号是不确定的。要对分区行进行排序,可以在窗口定义中使用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 |
    +------+---------+------------+--------+----------+----------+

如前所述,要使用窗口函数(或将聚合函数用作窗口函数),需要在函数调用之后使用OVER语句。OVER语句有两种形式:

  • over_clause:
        {OVER (window_spec) | OVER window_name}

这两种形式都定义了窗口函数应该如何处理查询行。它们的不同之处在于窗口是直接在OVER语句中定义的,还是由查询中其他地方定义的指定窗口的引用提供的:

    1)在第一种情况下,窗口规范直接出现在OVER语句的圆括号之间;

    2)在第二种情况下,window_name是查询中其他地方的window语句定义的窗口规范的名称。有关详细信息,请参见Section 12.21.4, “Named Windows”。

对于OVER (window_spec)语法,窗口规范有几个部分,都是可选的:

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

如果OVER()为空,则窗口由所有查询行组成,窗口函数使用所有行计算结果。否则,括号内的子句将决定使用哪些查询行来计算函数结果,以及如何对它们进行分区和排序:

    1)window_name:由查询中其他地方的window语句定义的窗口的名称。如果在OVER语句中单独出现window_name,它将完全定义窗口。如果还提供了分区、排序或框架子句,它们将修改对指定窗口的解释。详细信息,可以参考Section 12.21.4, “Named Windows”。

    2)partition_clause:PARTITION BY子句指示如何将查询行划分为组。给定行的窗口函数结果基于包含该行的分区行。如果省略PARTITION BY,则有一个由所有查询行组成的分区。

        Note: 窗口函数的分区不同于表分区。有关表分区的信息,请参见Chapter 23, Partitioning

    partition_clause的语法如下:

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

    标准SQL只要求PARTITION BY后跟列名。MySQL的一个扩展是允许表达式,而不仅仅是列名。例如,如果一个表包含一个名为ts的时间戳列,那么标准SQL允许按ts而不是HOUR(ts)进行分区,而MySQL则两者都允许。

    3)order_clause:ORDER BY子句指示如何对每个分区中的行进行排序。根据ORDER BY子句得到的相等的分区行被认为是对等的。如果省略ORDER BY,分区行是无序的,没有隐式处理顺序的话,所有分区行都是对等的。

    order_clause语法如下:

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

    每个ORDER BY表达式可以选择后跟ASC或DESC来指示排序方向。如果没有指定方向,则默认为ASC。NULL值首先用于升序排序,最后用于降序排序。

    窗口定义中的ORDER BY应用于各个分区。要对结果集进行整体排序,可以在查询顶层使用ORDER BY语句。

   4)frame_clause:框架是当前分区的一个子集,框架语句指定如何定义这个子集。框架语句本身有许多子句。详细信息,可以参考Section 12.21.3, “Window Function Frame Specification”。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~我是分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下一篇:https://blog.csdn.net/qq_41080850/article/details/86416248(MySQL窗口函数中frame子句的用法)

参考:http://www.mysqltutorial.org/mysql-window-functions/

PS:鉴于水平有限,译文中难免存在谬误,欢迎批评指正。

你可能感兴趣的:(MySQL,MySQL窗口函数)