当前位置:   article > 正文

MySQL8 新特性——窗口函数用法_mysql 8.0 窗口函数

mysql 8.0 窗口函数

目录

窗口函数

分类

排名函数(Ranking Functions):

聚合函数(Aggregate Functions):

分析函数(Analytic Functions):

静态/动态窗口函数

语法结构

部分函数用法介绍

ROW_NUMBER()

RANK()

DENSE_RANK()

PERCENT_RANK()

CUME_DIST()

LAG(expr, n)、LEAD(expr, n)

FIRST_VALUE(expr)、LAST_VALUE(expr)

NTH_VALUE(expr, n)

NTILE(n)

总结


MySQL 8.0 是 MySQL 数据库管理系统的一个重要版本,引入了许多新特性和改进。以下是 MySQL 8.0 的一些主要新特性:

  1. 事务隔离级别改进: MySQL 8.0 引入了新的事务隔离级别 SERIALIZABLE,提供了最高级别的事务隔离,确保了数据的完整性和一致性。同时,它对其他事务隔离级别的实现也进行了改进,提高了并发性和性能。
  2. Window Functions 支持: MySQL 8.0 引入了窗口函数(Window Functions)的支持,使得在查询中进行复杂的分析和聚合变得更加灵活和高效。窗口函数可以与 OVER 子句一起使用,实现分组、排序、排名等操作。
  3. Common Table Expressions (CTEs) 支持: MySQL 8.0 支持通用表达式(CTEs),允许在查询中使用 WITH 子句来定义临时结果集,简化了复杂查询的编写。
  4. JSON 支持改进: MySQL 8.0 对 JSON 支持进行了改进,包括支持更多的 JSON 函数和操作,以及更高效的 JSON 存储格式,使得在 MySQL 中存储和查询 JSON 数据更加方便。
  5. 新增 Data Dictionary: MySQL 8.0 引入了 Data Dictionary 来替代之前的 .frm 文件,用于存储数据库元数据信息,提高了数据库的可靠性和扩展性。
  6. InnoDB 存储引擎改进: MySQL 8.0 对 InnoDB 存储引擎进行了多项改进,包括支持更大的表空间、在线表重建、数据压缩和加密、性能优化等。
  7. 全局事务标识(GTID)改进: MySQL 8.0 改进了全局事务标识(GTID)的支持,简化了主从复制配置和管理,提高了复制的可靠性。
  8. Persistent Configuration Variables: MySQL 8.0 引入了持久配置变量,允许将配置参数的值持久化到配置文件中,重启后仍然保持设置。
  9. 离线数据迁移: MySQL 8.0 支持通过 ALTER TABLE 命令进行离线数据迁移,不再需要使用 pt-online-schema-change 工具。
  10. 二进制日志改进: MySQL 8.0 对二进制日志进行了改进,包括支持多线程写入、事务重放和文件格式改进,提高了日志的性能和可靠性。

以上只是 MySQL 8.0 的一部分新特性,该版本还有许多其他改进,如更好的性能、安全性和扩展性等。MySQL 8.0 的发布为用户提供了更多的功能和选项,使得 MySQL 数据库成为更强大和可靠的数据库解决方案。

窗口函数

窗口函数的作用类似于在查询中对数据进行分组,不同的是,分组操作会把分组的结果聚会成一条记录,而窗口函数是将结果置于每一条数据记录中。窗口函数可以用来处理复杂的报表统计分析场景,例如计算移动平均值、累计和、排名等。其中博主认为它展现的主要威力在于「它能够让我们在不修改原有语句输出结果的基础上,直接添加新的聚合字段」

分类

窗口函数可以根据其功能和用途进行分类。在MySQL中,根据其功能,窗口函数主要可以分为以下几类:

排名函数(Ranking Functions):

  • ROW_NUMBER(): 返回每行在结果集中的唯一编号。
  • RANK(): 计算并返回排序后的行在结果集中的排名,相同值有相同的排名,跳过相同排名。
  • DENSE_RANK(): 计算并返回排序后的行在结果集中的排名,相同值有相同的排名,不跳过相同排名。
  • NTILE(n): 将结果集划分为n个近似相等大小的桶,并为每行分配一个桶编号。

聚合函数(Aggregate Functions):

  • SUM(): 对窗口中的数值列进行求和。
  • AVG(): 对窗口中的数值列进行求平均值。
  • MIN(): 返回窗口中数值列的最小值。
  • MAX(): 返回窗口中数值列的最大值。
  • COUNT(): 返回窗口中行的数量。累积函数(Aggregate Functions with ORDER BY):
  • SUM() OVER (): 对窗口中的数值列进行累积求和。
  • AVG() OVER (): 对窗口中的数值列进行累积求平均值。
  • MIN() OVER (): 返回窗口中数值列的累积最小值。
  • MAX() OVER (): 返回窗口中数值列的累积最大值。

分析函数(Analytic Functions):

  • LEAD(): 获取当前行后面指定偏移量的行的值。
  • LAG(): 获取当前行前面指定偏移量的行的值。
  • FIRST_VALUE(): 返回窗口中指定列的第一个值。
  • LAST_VALUE(): 返回窗口中指定列的最后一个值。
  • PERCENT_RANK(): 计算并返回排序后的行在结果集中的百分比排名。(rank - 1) / (rows - 1)
  • CUME_DIST(): 计算并返回排序后的行在结果集中的累积分布百分比。

这些是窗口函数的常见分类,每个类别有不同的用途和计算功能,可以根据具体的数据处理需求选择合适的窗口函数来实现复杂的查询和分析操作。

静态/动态窗口函数

实际上,窗口函数在MySQL中并没有严格的"静态"和"动态"分类。窗口函数通常根据其特性和功能进行分类,如我之前所述的排名函数、聚合函数、累积函数和分析函数等。这些分类基于窗口函数的不同计算方式和用途。

然而,可能你提到的"静态窗口函数"和"动态窗口函数"是指窗口函数在窗口帧(Window Frame)中的范围设置方式。窗口帧定义了在计算窗口函数时,应该包含哪些行。在MySQL中,有两种常见的窗口帧设置方式:

  1. 静态窗口函数(Static Window Functions):在静态窗口函数中,窗口帧的范围是固定的,不随行的位置变化而改变。最常见的静态窗口帧是使用ROWS BETWEEN子句,指定相对于当前行的固定范围来定义窗口。
    1. SELECT
    2. column1,
    3. column2,
    4. SUM(column3) OVER (ORDER BY column1 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS sum_column3
    5. FROM
    6. your_table;

    在上述例子中,使用ROWS BETWEEN 2 PRECEDING AND CURRENT ROW定义了一个静态窗口帧,窗口包含当前行以及前面两行的数据。以下面的数据举例:

    1. set @row_number:=0;
    2. SELECT
    3. @row_number:=@row_number +1 as num,
    4. stock,
    5. SUM(stock) OVER (ORDER BY stock ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS sum_stock
    6. FROM
    7. goods;


    去掉ROWS BETWEEN 2 PRECEDING AND CURRENT ROW,统计的就是当前行之前的所有行,不过这里有个问题,如果当前行和后面相邻的行数据一样,那就会把后面的行数据也统计了。

    1. set @row_number:=0;
    2. SELECT
    3. @row_number:=@row_number +1 as num,
    4. stock,
    5. SUM(stock) OVER (ORDER BY stock ) AS sum_stock
    6. FROM
    7. goods;


    如果要实现类似功能,换个写法:

    1. SET @num := 0;
    2. SELECT
    3. stock,
    4. @num := @num + stock AS sum_stock
    5. FROM
    6. goods
    7. ORDER BY
    8. stock;

  2. 动态窗口函数(Dynamic Window Functions):在动态窗口函数中,窗口帧的范围随着行的位置而变化。最常见的动态窗口帧是使用RANGE BETWEEN子句,基于值的范围来定义窗口。
    1. SELECT
    2. column1,
    3. column2,
    4. SUM(column3) OVER (ORDER BY column1 RANGE BETWEEN INTERVAL 1 HOUR PRECEDING AND CURRENT ROW) AS sum_column3
    5. FROM
    6. your_table;

    在上述例子中,使用RANGE BETWEEN INTERVAL 1 HOUR PRECEDING AND CURRENT ROW定义了一个动态窗口帧,窗口包含当前行及其前面1小时内的数据,根据时间的变化而自动调整范围。

    需要注意的是,动态窗口函数在MySQL中的支持有限,而且使用时需要谨慎,因为它可能涉及对窗口中的所有数据进行排序,对性能有一定的影响。大多数情况下,静态窗口函数已经能够满足大部分需求。

语法结构

在MySQL中,窗口函数的语法结构如下:

  1. <窗口函数> OVER (
  2. [PARTITION BY partition_expression]
  3. [ORDER BY sort_expression [ASC | DESC], ...]
  4. [window_frame]
  5. )

让我们逐个解释每个部分的含义:

  1. <窗口函数>:这是要执行的窗口函数,可以是聚合函数(如SUM()、AVG()、MIN()、MAX()、COUNT()等)、排名函数(如ROW_NUMBER()、RANK()、DENSE_RANK()、NTILE()等)或其他分析函数(如LEAD()、LAG()、FIRST_VALUE()、LAST_VALUE()、PERCENT_RANK()、CUME_DIST()等)。
  2. OVER ():这是定义窗口的关键字,它后面跟着圆括号,用于包含窗口的设置。
  3. PARTITION BY partition_expression:这是可选的子句,用于将结果集分成不同的分区(组)。partition_expression是一个表达式,根据它的值来划分不同的分区。窗口函数将在每个分区内独立计算。
  4. ORDER BY sort_expression [ASC | DESC], ...:这也是可选的子句,用于在每个分区内对数据进行排序。sort_expression是一个表达式,用于指定排序的规则。可以指定多个排序表达式,并可以指定升序(ASC)或降序(DESC)。
  5. window_frame:这是可选的子句,用于指定在每个分区中用于窗口函数的行范围。它决定了哪些行包含在计算中。窗口帧可以基于当前行的相对位置(ROWS [n] PRECEDING或FOLLOWING)或基于列的值(RANGE BETWEEN value1 AND value2)。如果未指定window_frame,则窗口函数默认使用所有分区中的所有行。

    CURRENT ROW: 表示当前行。
    UNBOUNDED PRECEDING: 表示分区中的第一行。
    UNBOUNDED FOLLOWING: 表示分区中的最后一行。
    expr PRECEDING: 表示当前行减去expr的值。
    expr FOLLOWING: 表示当前行加上expr的值。

    例如,如果指定了ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING,则表示窗口范围包括当前行、前两行和后一行。如果指定了RANGE BETWEEN 10 PRECEDING AND CURRENT ROW,则表示窗口范围包括当前行和值在当前行减去10以内的所有行。如果没有指定frame_clause,则默认为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即从分区开始到当前行。

请注意,窗口函数的具体语法可能因数据库管理系统的版本而有所不同。以上语法适用于MySQL 8.0及以上版本,其他数据库系统(如SQL Server、PostgreSQL等)的语法可能稍有不同。在使用时请根据具体的数据库版本和语法规则进行相应调整。

部分函数用法介绍

  1. #准备工作
  2. CREATE TABLE goods
  3. (
  4. id INT PRIMARY KEY AUTO_INCREMENT,
  5. category_id INT,
  6. category VARCHAR(15),
  7. NAME VARCHAR(30),
  8. price DECIMAL(10, 2),
  9. stock INT,
  10. upper_time DATETIME
  11. );
  12. INSERT INTO goods (category_id, category, NAME, price, stock, upper_time)
  13. VALUES (1, '女装/女士精品', 'Th', 39.90, 1000, '2023-7-23 00:00:00'),
  14. (1, '女装/女士精品', '连衣裙', 79.98, 2500, '2023-7-23 00:00:00'),
  15. (1, '女装/女士精品', '卫衣', 89.98, 1500, '2023-7-23 00:00:00'),
  16. (1, '女装/女士精品', '牛仔裤', 89.98, 3500, '2023-7-23 00:00:00'),
  17. (1, '女装/女士精品', '百智精', 29.98, 500, '2023-7-23 00:00:00'),
  18. (1, '女装/女士精品', '呢绒外套', 399.98, 128, '2023-7-23 00:00:00'),
  19. (2, '户外运动', '自行车', 399.98, 2300, '2023-7-23 00:00:00'),
  20. (2, '户外运动', '山地自行车', 1399.98, 2500, '2023-7-23 00:00:00'),
  21. (2, '户外运动', '连山秋', 59.98, 1599, '2023-7-23 00:00:00'),
  22. (2, '户外运动', '骑行装备', 399.98, 3568, '2023-7-23 00:00:00'),
  23. (2, '户外运动', '运动外套', 799.98, 500, '2023-7-23 00:00:00'),
  24. (2, '户外运动', '滑板', 499.9, 1200, '2023-7-23 00:00:00');

ROW_NUMBER()

  1. ## ROW_NUMBER()
  2. # 查询每个商品分类下 再按价格降序排序信息
  3. SELECT ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
  4. FROM goods;

 

  1. # 查询每个商品分类下价格最高的3种商品信息
  2. SELECT *
  3. FROM (SELECT ROW_NUMBER() over (PARTITION BY category ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock FROM goods) t
  4. WHERE row_num <= 3;

RANK()

  1. # 和 ROW_NUMBER() 区别 当price价格一样时,ROW_NUMBER()返回123;而 RANK() 返回1224
  2. # 获取各个类别的价格从高到低排序
  3. SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
  4. FROM goods;

DENSE_RANK()

  1. # 返回的序号不会跳过重复的序号,比如返回1223
  2. SELECT DENSE_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
  3. FROM goods;

PERCENT_RANK()

  1. ## PERCENT_RANK()
  2. # 计算名称为"女装/女士精品"的类别下的商品的PERCENT_RANK值
  3. SELECT RANK() OVER w AS r,
  4. PERCENT_RANK() OVER w AS pr,
  5. id,
  6. category_id,
  7. category,
  8. NAME,
  9. price,
  10. stock
  11. FROM goods
  12. WHERE category_id = 1 WINDOW w AS (PARTITION BY category_id ORDER BY price DESC);
  13. # 写法方式二:
  14. SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS r,
  15. PERCENT_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS pr,
  16. id,
  17. category_id,
  18. category,
  19. NAME,
  20. price,
  21. stock
  22. FROM goods
  23. WHERE category_id = 1;

CUME_DIST()

  1. # 主要用于查询小于或等于当前价格的比例
  2. SELECT CUME_DIST() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
  3. FROM goods;

LAG(expr, n)、LEAD(expr, n)

  1. ## LAG(expr, n)
  2. # 返回当前行的前n行的expr的值
  3. # 查询前一个商品与当前商品价格的差值
  4. # 之前遇到过一个求历史修改记录差异可以用这个!!!,当时听负责人的加了parent_id
  5. SELECT id,
  6. category_id,
  7. category,
  8. NAME,
  9. price,
  10. price - pre_price AS diff_prive,
  11. pre_price,
  12. pre_id
  13. FROM (SELECT id, category_id, category, NAME, price, LAG(price, 1) OVER (ORDER BY price) AS pre_price, LAG(id, 1) OVER ( ORDER BY price) AS pre_id
  14. FROM goods) t;
  15. ## LEAD(expr, n)
  16. # 返回当前行的后n行的expr的值,类似⬆️

可用于统计每个月的增幅 (当月-上月)/ 当月

FIRST_VALUE(expr)、LAST_VALUE(expr)

  1. ## FIRST_VALUE(expr)
  2. # 返回第一个expr的值
  3. SELECT id, category_id, category, NAME, price, stock, FIRST_VALUE(price) OVER (PARTITION BY category_id ORDER BY price) AS first_price
  4. FROM goods;
  5. ## LAST_VALUE(expr)
  6. # 返回最后一个expr的值

NTH_VALUE(expr, n)

  1. ## NTH_VALUE(expr, n)
  2. # 查询排名第2和第3的价格信息
  3. SELECT id,
  4. category,
  5. NAME,
  6. price,
  7. NTH_VALUE(price, 2) OVER (PARTITION BY category_id ORDER BY price) AS second_price,
  8. NTH_VALUE(price, 3) OVER (PARTITION BY category_id ORDER BY price) AS third_price
  9. FROM goods;

NTILE(n)

  1. ## NTILE(n) 分为n组
  2. SELECT NTILE(4) OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
  3. FROM goods;

总结

 窗口函数的特点是可以分组,而且可以在分组内排序。另外,窗口函数不会因为分组减少原表中的行数,这对我们在原表数据的基础上进行统计和排序非常有用。

————————————————
版权声明:本文为CSDN博主「WalkingWithTheWind~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a2272062968/article/details/131880617

相关文章:MySQL8新特性窗口函数详解

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/702230
推荐阅读
相关标签
  

闽ICP备14008679号