在这篇文章中,我们将了解不同类型的MySQL窗口函数,以及如何根据不同的使用情况来使用它们。MySQL是当今软件世界中最常用的数据库之一。几乎所有正在运行的网络应用程序都使用MySQL作为数据库,无论是在企业内部还是在云端。对于开发人员和数据库用户来说,掌握他们的查询能力变得极为必要,这样他们就可以根据要求查询数据库并产生合适的结果。在这篇文章中,我们将重点介绍MySQL窗口函数以及如何通过实际例子来使用它们。需要注意的一点是,大多数MySQL窗口函数只适用于8或更高版本。
什么是窗口函数?
为了理解MySQL窗口函数,让我们首先理解SQL中的窗口函数是什么意思。在SQL中,窗口函数是特殊类型的预建函数,它从一组行中为每一行返回一个值。 这在开始时可能听起来很混乱,但并不复杂。简单地说,一个窗口函数,为上下文中的每一行从多条记录中计算出数值。让我们通过一个简单的例子来理解这一点。
图1 - 了解窗口函数在SQL中如何工作的样本数据
让我们考虑一下,我们有一个班级的数据,这个班级有八个学生,分成两个系。班里的每个学生都有一个专用的唯一的学生号。然而,为了方便起见,各系主任决定每个学生在本系内也应该得到一个学生号。如果你考虑上图,右边那一栏正好做到了这一点,即为每个学生提供一个系内专用的学生号。 这是一个窗口函数的例子,一旦系里发生变化,学生号就会重置。在这种情况下,由于学生的数量相当少,可以手动分配特定部门的学生编号。 然而,如果班级有超过数百名跨多个部门的学生,使用SQL来分配编号是最安全的选择。
在SQL中,基本上有两种类型的窗口函数 - 聚合窗口函数和分析窗口函数。
- 聚合窗口函数 - 顾名思义,这些类型的窗口函数计算的是表中一组行的聚合值。聚合窗口函数的一些例子是SUM, AVG, MIN, MAX等。你需要使用GROUP BY子句,以便将这些聚合窗口函数与其他一些列一起使用。这通常会返回一个标量值
- 分析性窗口函数- 这些类型的函数是用来根据当前行计算一些窗口,然后根据该窗口记录计算结果。其结果通常以SQL中的多条记录的形式返回。常见的例子包括RANK, DENSE_RANK, CUME_DIST, RANK, LEAD, LAG, 等等。
现在让我们详细探讨一下这些函数。
MySQL中的聚合窗口函数
现在让我们尝试探索一下简单的聚合窗口函数。
SUM窗口函数
SUM窗口函数计算给定窗口中一个数字列的总数。如果没有要分组的列,这将返回一个标量值。如果我们需要找到每组的总数,我们可以使用GROUP BY子句来获得每行的总数。
图2 - 按学生分组的总分
AVG窗口函数
AVG窗口函数是用来查找数字列的平均值的。它的工作方式与SUM函数的工作方式相同,只是它返回的是平均值。
图3 - 每个学生的平均分数
MIN和MAX窗口函数
MIN和MAX窗口函数用于计算一个窗口内的最小值和最大值。如果窗口内只有单行,那么它将只返回该行的具体数值。
图4 - 在MySQL窗口函数中计算MIN和MAX
正如你在上图中所看到的,学生Jason和Tom分别有两门学科,因此对他们分别计算最小值和最大值。
COUNT窗口函数
COUNT函数用于计算给定窗口内的记录数量。它可以和DISTINCT子句一起使用,计算给定窗口内的不同值。
图5 - 使用DISTINCT子句计算窗口内的学生总数
MySQL中的分析性窗口函数
在上一节中已经提到,分析性窗口函数有点特别,因为它们在单行的范围内对行的窗口进行工作。让我们尝试探索一下不同类型的分析性窗口函数。
ROW_NUMBER窗口函数
这是MySQL中最简单的分析性窗口函数之一。这个函数只是为表内或所选记录窗口内的每条记录分配一个递增的行号。
图6 - 在MySQL中计算行数
正如你在上图中所看到的,所有的记录都按照标记的升序进行排序,然后为每一行分配了一个递增的行号。这个行号是在查询执行时动态生成的,并且会随着学生在表中的分数变化而变化。
此外,我们还可以使用带有系名的PARTITION BY子句来创建一个窗口,一旦系名发生变化,就会重新设置行号。
图7 - 使用PARTITION BY子句来生成行号
正如你在上图中看到的,当部门发生变化时,行号会自动重置。排序顺序仍然保持在SQL查询中提到的标记的递增顺序上。
MySQL中的RANK和DENSE RANK窗口函数
排名与行号几乎相似,事实上,在排名中会处理平局,而在行号函数中则不处理。平局是指两个或更多的记录具有相同的数值,而该函数已被应用到这些记录上。在RANK函数中,领带将被分配相同的数字。例如,如果你在等级2有三个并列记录,那么接下来列出的等级将是5而不是3。为了避免这种情况,我们有一个叫做DENSE RANK的函数。DENSE RANK将处理平局而不跳过行数。现在让我们通过一些例子来看看。
图8 - 在MySQL中使用RANK和DENSE_RANK函数
正如你在上图中看到的,我们有两列RANK和DENSE RANK函数。RANK函数将最后一条记录列为10,而DENSE RANK函数将其列为8。
这些是一些正在使用的最常见的MySQL窗口函数。尽管还有一些其他的分析函数,如累积分布、NTile等,但这些已经超出了本文的范围。
总结
在这篇文章中,我们已经了解了可在MySQL数据库中使用的不同类型的MySQL窗口函数。MySQL在很大程度上被全球的许多组织所使用,因此绝对有必要学习MySQL的高级概念。MySQL的窗口函数与其他流行的数据库如SQL Server和PostgreSQL等的窗口函数非常相似。理解窗口函数的概念将帮助你更好地理解如何在上下文中为每一行选择多行,然后将函数应用于它们。