赞
踩
目录
FIRST_VALUE(expr)、LAST_VALUE(expr)
MySQL 8.0 是 MySQL 数据库管理系统的一个重要版本,引入了许多新特性和改进。以下是 MySQL 8.0 的一些主要新特性:
以上只是 MySQL 8.0 的一部分新特性,该版本还有许多其他改进,如更好的性能、安全性和扩展性等。MySQL 8.0 的发布为用户提供了更多的功能和选项,使得 MySQL 数据库成为更强大和可靠的数据库解决方案。
窗口函数的作用类似于在查询中对数据进行分组,不同的是,分组操作会把分组的结果聚会成一条记录,而窗口函数是将结果置于每一条数据记录中。窗口函数可以用来处理复杂的报表统计分析场景,例如计算移动平均值、累计和、排名等。其中博主认为它展现的主要威力在于「它能够让我们在不修改原有语句输出结果的基础上,直接添加新的聚合字段」。
窗口函数可以根据其功能和用途进行分类。在MySQL中,根据其功能,窗口函数主要可以分为以下几类:
这些是窗口函数的常见分类,每个类别有不同的用途和计算功能,可以根据具体的数据处理需求选择合适的窗口函数来实现复杂的查询和分析操作。
实际上,窗口函数在MySQL中并没有严格的"静态"和"动态"分类。窗口函数通常根据其特性和功能进行分类,如我之前所述的排名函数、聚合函数、累积函数和分析函数等。这些分类基于窗口函数的不同计算方式和用途。
然而,可能你提到的"静态窗口函数"和"动态窗口函数"是指窗口函数在窗口帧(Window Frame)中的范围设置方式。窗口帧定义了在计算窗口函数时,应该包含哪些行。在MySQL中,有两种常见的窗口帧设置方式:
- SELECT
- column1,
- column2,
- SUM(column3) OVER (ORDER BY column1 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS sum_column3
- FROM
- your_table;
在上述例子中,使用ROWS BETWEEN 2 PRECEDING AND CURRENT ROW定义了一个静态窗口帧,窗口包含当前行以及前面两行的数据。以下面的数据举例:
- set @row_number:=0;
- SELECT
- @row_number:=@row_number +1 as num,
- stock,
- SUM(stock) OVER (ORDER BY stock ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS sum_stock
- FROM
- goods;
去掉ROWS BETWEEN 2 PRECEDING AND CURRENT ROW,统计的就是当前行之前的所有行,不过这里有个问题,如果当前行和后面相邻的行数据一样,那就会把后面的行数据也统计了。
- set @row_number:=0;
- SELECT
- @row_number:=@row_number +1 as num,
- stock,
- SUM(stock) OVER (ORDER BY stock ) AS sum_stock
- FROM
- goods;
如果要实现类似功能,换个写法:
- SET @num := 0;
- SELECT
- stock,
- @num := @num + stock AS sum_stock
- FROM
- goods
- ORDER BY
- stock;
- SELECT
- column1,
- column2,
- SUM(column3) OVER (ORDER BY column1 RANGE BETWEEN INTERVAL 1 HOUR PRECEDING AND CURRENT ROW) AS sum_column3
- FROM
- your_table;
在上述例子中,使用RANGE BETWEEN INTERVAL 1 HOUR PRECEDING AND CURRENT ROW定义了一个动态窗口帧,窗口包含当前行及其前面1小时内的数据,根据时间的变化而自动调整范围。
需要注意的是,动态窗口函数在MySQL中的支持有限,而且使用时需要谨慎,因为它可能涉及对窗口中的所有数据进行排序,对性能有一定的影响。大多数情况下,静态窗口函数已经能够满足大部分需求。
在MySQL中,窗口函数的语法结构如下:
- <窗口函数> OVER (
- [PARTITION BY partition_expression]
- [ORDER BY sort_expression [ASC | DESC], ...]
- [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等)的语法可能稍有不同。在使用时请根据具体的数据库版本和语法规则进行相应调整。
- #准备工作
- CREATE TABLE goods
- (
- id INT PRIMARY KEY AUTO_INCREMENT,
- category_id INT,
- category VARCHAR(15),
- NAME VARCHAR(30),
- price DECIMAL(10, 2),
- stock INT,
- upper_time DATETIME
- );
-
- INSERT INTO goods (category_id, category, NAME, price, stock, upper_time)
- VALUES (1, '女装/女士精品', 'Th', 39.90, 1000, '2023-7-23 00:00:00'),
- (1, '女装/女士精品', '连衣裙', 79.98, 2500, '2023-7-23 00:00:00'),
- (1, '女装/女士精品', '卫衣', 89.98, 1500, '2023-7-23 00:00:00'),
- (1, '女装/女士精品', '牛仔裤', 89.98, 3500, '2023-7-23 00:00:00'),
- (1, '女装/女士精品', '百智精', 29.98, 500, '2023-7-23 00:00:00'),
- (1, '女装/女士精品', '呢绒外套', 399.98, 128, '2023-7-23 00:00:00'),
- (2, '户外运动', '自行车', 399.98, 2300, '2023-7-23 00:00:00'),
- (2, '户外运动', '山地自行车', 1399.98, 2500, '2023-7-23 00:00:00'),
- (2, '户外运动', '连山秋', 59.98, 1599, '2023-7-23 00:00:00'),
- (2, '户外运动', '骑行装备', 399.98, 3568, '2023-7-23 00:00:00'),
- (2, '户外运动', '运动外套', 799.98, 500, '2023-7-23 00:00:00'),
- (2, '户外运动', '滑板', 499.9, 1200, '2023-7-23 00:00:00');
- ## ROW_NUMBER()
- # 查询每个商品分类下 再按价格降序排序信息
- SELECT ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
- FROM goods;
- # 查询每个商品分类下价格最高的3种商品信息
- SELECT *
- 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
- WHERE row_num <= 3;
- # 和 ROW_NUMBER() 区别 当price价格一样时,ROW_NUMBER()返回1,2,3;而 RANK() 返回1,2,2,4
- # 获取各个类别的价格从高到低排序
- SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
- FROM goods;
- # 返回的序号不会跳过重复的序号,比如返回1,2,2,3
- SELECT DENSE_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
- FROM goods;
- ## PERCENT_RANK()
- # 计算名称为"女装/女士精品"的类别下的商品的PERCENT_RANK值
- SELECT RANK() OVER w AS r,
- PERCENT_RANK() OVER w AS pr,
- id,
- category_id,
- category,
- NAME,
- price,
- stock
- FROM goods
- WHERE category_id = 1 WINDOW w AS (PARTITION BY category_id ORDER BY price DESC);
- # 写法方式二:
- SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS r,
- PERCENT_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS pr,
- id,
- category_id,
- category,
- NAME,
- price,
- stock
- FROM goods
- WHERE category_id = 1;
- # 主要用于查询小于或等于当前价格的比例
- SELECT CUME_DIST() OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
- FROM goods;
- ## LAG(expr, n)
- # 返回当前行的前n行的expr的值
- # 查询前一个商品与当前商品价格的差值
- # 之前遇到过一个求历史修改记录差异可以用这个!!!,当时听负责人的加了parent_id
- SELECT id,
- category_id,
- category,
- NAME,
- price,
- price - pre_price AS diff_prive,
- pre_price,
- pre_id
- 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
- FROM goods) t;
-
- ## LEAD(expr, n)
- # 返回当前行的后n行的expr的值,类似⬆️
可用于统计每个月的增幅 (当月-上月)/ 当月
- ## FIRST_VALUE(expr)
- # 返回第一个expr的值
- SELECT id, category_id, category, NAME, price, stock, FIRST_VALUE(price) OVER (PARTITION BY category_id ORDER BY price) AS first_price
- FROM goods;
-
- ## LAST_VALUE(expr)
- # 返回最后一个expr的值
- ## NTH_VALUE(expr, n)
- # 查询排名第2和第3的价格信息
- SELECT id,
- category,
- NAME,
- price,
- NTH_VALUE(price, 2) OVER (PARTITION BY category_id ORDER BY price) AS second_price,
- NTH_VALUE(price, 3) OVER (PARTITION BY category_id ORDER BY price) AS third_price
- FROM goods;
- ## NTILE(n) 分为n组
- SELECT NTILE(4) OVER (PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock
- FROM goods;
窗口函数的特点是可以分组,而且可以在分组内排序。另外,窗口函数不会因为分组减少原表中的行数,这对我们在原表数据的基础上进行统计和排序非常有用。
————————————————
版权声明:本文为CSDN博主「WalkingWithTheWind~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a2272062968/article/details/131880617
相关文章:MySQL8新特性窗口函数详解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。