MySQL窗口函数及其分析查询

MySQL从版本8.0开始,支持窗口函数。窗口函数允许您以新的,更简单的方式解决查询问题,并具有更好的性能。

假设我们有一个sales表,按员工和财政年度存储销售额,如下所示:

CREATE TABLE sales(
    sales_employee VARCHAR(50) NOT NULL,
    fiscal_year INT NOT NULL,
    sale DECIMAL(14,2) NOT NULL,
    PRIMARY KEY(sales_employee,fiscal_year)
);
 
INSERT INTO sales(sales_employee,fiscal_year,sale)
VALUES('Bob',2016,100),
      ('Bob',2017,150),
      ('Bob',2018,200),
      ('Alice',2016,150),
      ('Alice',2017,100),
      ('Alice',2018,200),
       ('John',2016,200),
      ('John',2017,150),
      ('John',2018,250);
 
SELECT 
	* 
FROM 
	sales;

在这里插入图片描述
理解窗口函数可能更容易从聚合函数开始。

聚合函数将来自多行的数据汇总到单个结果行中。例如,以下SUM()函数返回记录年份中所有员工的总销售额:

SELECT 
	SUM(sale) 
FROM 
	sales;

在这里插入图片描述
该GROUP BY子句允许您将聚合函数应用于行的子集。例如,您可能希望按会计年度计算总销售额:

SELECT
    fiscal_year,
    SUM(sale)
FROM
    sales
GROUP BY
    fiscal_year;  

在这里插入图片描述
在这两个示例中,聚合函数都会减少查询返回的行数。

与带有GROUP BY子句的聚合函数一样,窗口函数也对行的子集进行操作,但它们不会减少查询返回的行数。

例如,以下查询返回每个员工的销售额,以及按会计年度计算的员工总销售额:

SELECT
    fiscal_year,
    sales_employee,
    sale,
    SUM(sale) OVER (PARTITION BY fiscal_year) total_sales
FROM
    sales;

在这里插入图片描述
在此示例中,该SUM()函数用作窗口函数,该函数对由OVER子句内容定义的一组行进行操作。SUM()应用该函数的一组行称为窗口。

该SUM()窗口函数由财政年度像它与查询报告不仅总销量GROUP BY条款,而且结果中的每一行中,而不是行的总数返回。

需要注意的是窗函数的结果集毕竟进行JOIN,WHERE,GROUP BY,以及HAVING条款和前ORDER BY,LIMIT和SELECT DISTINCT。

窗口函数语法

调用窗口函数的一般语法如下:

window_function_name(expression)
    OVER (
        [partition_defintion]
        [order_definition]
        [frame_definition]
    )

在这个语法中:
1、首先,指定窗口函数名称,后跟表达式。
2、其次,指定OVER具有三个可能元素的子句:分区定义,顺序定义和帧定义。

该OVER子句后面的开括号和右括号是强制性的,即使没有表达式,例如:

window_function_name(expression) OVER()

partition_clause 句法
将partition_clause行分成块或分区。两个分区由分区边界分隔。

窗口函数在分区内执行,并在跨越分区边界时重新初始化。

的partition_clause语法如下所示:

PARTITION BY <expression>[{,<expression>...}]

您可以在PARTITION BY子句中指定一个或多个表达式。多个表达式用逗号分隔。

order_by_clause 句法
该order_by_clause语法如下:

ORDER BY <expression> [ASC|DESC], [{,<expression>...}]

该ORDER BY子句指定行在分区中的排序方式。可以在多个键上的分区内对数据进行排序,每个键由表达式指定。多个表达式也用逗号分隔。

与该PARTITION BY子句类似ORDER BY,所有窗口函数也支持该子句。但是,仅对ORDER BY顺序敏感的窗口函数使用该子句才有意义。

frame_clause 句法

帧是当前分区的子集。要定义子集,请使用frame子句,如下所示:

frame_unit {<frame_start>|<frame_between>}

相对于当前行定义帧,这允许帧根据其分区内当前行的位置在分区内移动。

帧单位指定当前行和帧行之间的关系类型。它可以是ROWS或RANGE。当前行和帧行的偏移量是行号,如果帧单位是ROWS行值,则行值是帧单位RANGE。

所述frame_start和frame_between定义帧边界。

将frame_start包含下列之一:

1、UNBOUNDED PRECEDING:frame从分区的第一行开始。
2、N PRECEDING:第一个当前行之前的物理N行。N可以是文字数字或计算结果的表达式。
3、CURRENT ROW:当前计算的行
该frame_between如下:

BETWEEN frame_boundary_1 AND frame_boundary_2  

该frame_boundary_1和frame_boundary_2可各自含有下列之一:
1、frame_start:如前所述
2、UNBOUNDED FOLLOWING:框架结束于分区的最后一行。
3、N FOLLOWING:当前行之后的物理N行。
如果未frame_definition在OVER子句中指定,则MySQL默认使用以下帧:

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

在这里插入图片描述

MySQL窗口函数列表

下表显示了MySQL中的窗口函数:

NameDescription
CUME_DIST计算一组值中值的累积分布
DENSE_RANK根据ORDER BY子句为其分区中的每一行分配一个排名。它为具有相同值的行分配相同的排名。如果两行或更多行具有相同的等级,则排序值序列中将没有间隙
FIRST_VALUE返回指定表达式相对于窗口框架中第一行的值
LAG返回分区中当前行之前的第N行的值。如果不存在前一行,则返回NULL
LAST_VALUE返回指定表达式相对于窗口框架中最后一行的值
LEAD返回分区中当前行之后的第N行的值。如果不存在后续行,则返回NULL
NTH_VALUE从窗口框的第N行返回参数的值
NTILE将每个窗口分区的行分配到指定数量的已排名组中
PERCENT_RANK计算分区或结果集中行的百分位数
RANK与DENSE_RANK()功能类似,除了当两个或更多行具有相同等级时排序值序列中存在间隙
ROW_NUMBER为其分区中的每一行分配一个连续整数

版权声明:本文为weixin_41540084原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。