📜  MySQL窗口函数

📅  最后修改于: 2020-11-19 01:00:55             🧑  作者: Mango

MySQL窗口函数

MySQL中的窗口函数,用于跨一组与当前行相关的行进行计算。当前行是发生函数评估的那一行。窗口函数执行的计算类似于使用聚合函数进行的计算。但是,与对整个表执行操作的聚合函数不同,窗口函数不会产生要分组为一行的结果。这意味着窗口函数对一组行执行操作,并为每行产生一个汇总值。因此,每一行都保持唯一标识。

窗口函数是MySQL版本8中引入的新功能,可提高查询的执行性能。这些功能使我们可以更有效地解决与查询有关的问题。

句法

以下是使用窗口函数的基本语法:

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

从语法上可以看出,我们首先指定了窗口函数的名称,然后是表达式。然后,我们指定OVER子句,该子句包含三个表达式,分别是partition_definition,order_definition和frame_definition。

它可以确保OVER子句始终有一个开括号和闭括号,即使它没有任何表达式也是如此。

让我们看看OVER子句中使用的每个表达式的语法:

分区条款

此子句用于将行划分或划分为多个分区,分区边界将这些分区分开。窗口函数在每个分区上运行,当它越过分区边界时,它将再次初始化。该子句的语法如下:

PARTITION BY [{,...}]

在partition子句中,我们可以定义一个或多个用逗号分隔的表达式。

按条款订购

此子句用于指定分区中行的顺序。以下是ORDER BY子句的语法:

ORDER BY  [ASC|DESC], [{,...}]

我们还可以使用它对多个键的分区中的行进行排序,其中每个键由表达式指定。此子句还可以定义一个或多个用逗号分隔的表达式。尽管ORDER BY子句可以与所有窗口函数一起使用,但建议将其与顺序敏感的窗口函数。

框架条款

框架是窗口函数中当前分区的子集。因此,我们使用frame子句定义当前分区的子集。使用frame子句创建当前分区的子集的语法如下:

frame_unit {|}

我们可以使用当前行定义一个Frame,该Frame允许相对于当前行的位置在分区内移动。

在语法中,可以是ROWS或RANGE的frame_unit负责定义帧行和当前行之间的关系类型。如果frame_unit是ROWS,则帧行和当前行的偏移量是行号。如果frame_unit为RANGE,则偏移量为行值。

frame_start和frame_between表达式用于指定帧边界。 frame_start表达式具有三件事:

无限制的前提:此处,帧从当前分区的第一行开始。

N开头:在这里,N是一个字面量数字或一个以数字求值的表达式。它是第一个当前行之前的行数。

当前行:它指定最近计算的行

frame_between表达式可以写成:

BETWEEN frame_boundary_1 AND frame_boundary_2

上面的表达式可以具有以下内容之一:

frame_start:我们之前已经解释过了。

UNBOUNDED FOLLOWING:它指定分区最后一行中帧的结尾。

N跟随:它是第一个当前行之后的实际N行。

如果未在OVER子句中指定frame_definition,则默认情况下,MySQL使用以下框架:

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

窗口功能概念

在本节中,我们将看到如何在MySQL中使用window函数。因此,让我们首先使用以下语句创建一个名为“ Sales”的表:

CREATE TABLE Sales(
    Employee_Name VARCHAR(45) NOT NULL,
    Year INT NOT NULL,
            Country VARCHAR(45) NOT NULL,
    Product VARCHAR(45) NOT NULL,
    Sale DECIMAL(12,2) NOT NULL,
    PRIMARY KEY(Employee_Name, Year)
);

接下来,我们必须使用INSERT语句将记录添加到表中,如下所示:

INSERT INTO Sales(Employee_Name, Year, Country, Product, Sale)
VALUES('Joseph', 2017, 'India', 'Laptop', 10000),
('Joseph', 2018, 'India', 'Laptop', 15000),
('Joseph', 2019, 'India', 'TV', 20000),
('Bob', 2017, 'US', 'Computer', 15000),
('Bob', 2018, 'US', 'Computer', 10000),
('Bob', 2019, 'US', 'TV', 20000),
('Peter', 2017, 'Canada', 'Mobile', 20000),
('Peter', 2018, 'Canada', 'Calculator', 1500),
('Peter', 2019, 'Canada', 'Mobile', 25000);

要将记录验证为表,请使用SELECT语句:

mysql> SELECT * FROM Sales;

执行后,我们可以看到记录已成功添加到表中。

为了理解窗口函数,让我们首先看看聚合函数如何在MySQL中工作。聚合函数评估多行并将结果集生成为一行。因此,执行以下使用聚合函数“ SUM”的语句,并返回给定年份所有雇员的总销售额:

mysql> SELECT SUM(sale) AS Total_Sales FROM Sales;

输出量

同样,我们将“ SUM”函数与对行子集起作用的GROUP BY子句一起使用。因此,执行以下语句,返回特定年份所有产品组的总销售额:

mysql> SELECT Year, Product, SUM(Sale) AS Total_Sales 
FROM Sales 
GROUP BY Year 
ORDER BY Product;

输出量

在这两个示例中,我们可以看到聚合函数将查询执行后的行数减少为单行。

与聚合函数类似,窗口函数也可以处理行的子集,但不会将结果集缩小为一行。这意味着窗口函数对一组行执行操作,并为每行产生一个汇总值。例如,执行以下语句,返回给定年份的每种产品的销售以及产品的总销售额:

mysql> SELECT Year, Product, Sale, SUM(Sale) 
OVER(PARTITION BY Year) AS Total_Sales 
FROM Sales;

输出量

在上面的示例中,我们可以看到window操作使用OVER子句,该子句负责将查询行划分为window函数处理的组。在这里,OVER子句按年份对行进行分区,并在每个分区上产生一个总和。成功计算之后,它将产生与每个分区行相对应的总和。

窗口功能的类型

我们可以将窗口函数主要分为以下三种类型:

汇总功能

它是对多行进行操作并在单行中产生结果的函数。一些重要的聚合函数是:

COUNT,SUM,AVG,MIN,MAX等。

排名功能

它是一项函数,允许我们在给定表中对分区的每一行进行排名。一些重要的排名功能是:

RANK,DENSE_RANK,PERCENT_RANK,ROW_NUMBER,CUME_DIST等。

分析功能

它是一个函数,由幂级数局部表示。一些重要的分析功能是:

NTILE,LEAD,LAG,NTH,FIRST_VALUE,LAST_VALUE等

分析函数示例

在这里,我们将使用NTILE窗口函数。此函数采用整数值作为参数,该参数将组划分为多个整数值。例如,如果我们使用NTILE(4),则它将总记录分为四组。当总记录为奇数时,它将奇数记录添加到第一行。以下查询对其进行了更清晰的说明。

SELECT Year, Product, Sale, 
NTile(4) OVER() AS Total_Sales 
FROM Sales;

输出量

在上面的输出中,我们可以看到总共有9行。因此,NTILE函数将其分为四行,并且将在第一行中添加一个额外的行。

让我们看看使用“ LEAD”函数的另一个示例。此函数用于查询表中的多个行而无需联接表本身。这意味着我们可以访问当前行中下一行的数据。它返回下一行的输出。执行以下语句以更清楚地理解它:

SELECT Year, Product, Sale, 
LEAD(Sale,1) OVER(ORDER BY Year) AS Total_Sales 
FROM Sales;

输出量