Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL 窗口函数计算

MySQL8.0实现窗口函数计算同比环比

作者:竣峰

本文主要介绍了MySQL8.0实现窗口函数计算同比环比,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

我们在业务中常常需要统计这个月销售量多少,同比增加多少,环比增加多少。这篇博文我们就看看如何利用窗口函数实现同比及环比的计算。

用到的关键字包括:lag, window

准备工作

首先我们得有MySQL 8.0及以上版本, 然后我们准备一张统计表。

CREATE TABLE `my_stat` (
  `month` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `profit` decimal(10,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

表里的内容如下:

monthprofit
2022-0510.00
2022-0612.00
2022-076.00
2022-0830.00
2022-0920.00
2022-108.00
2022-112.00
2022-124.00
2023-0114.00
2023-0210.00
2023-038.00
2023-049.00
2023-057.00
2023-0610.00
2023-0715.00

数据 插入的SQL

INSERT INTO `my_stat` (`month`, `profit`)
VALUES
  ('2022-05', 10.00),
  ('2022-06', 12.00),
  ('2022-07', 6.00),
  ('2022-08', 30.00),
  ('2022-09', 20.00),
  ('2022-10', 8.00),
  ('2022-11', 2.00),
  ('2022-12', 4.00),
  ('2023-01', 14.00),
  ('2023-02', 10.00),
  ('2023-03', 8.00),
  ('2023-04', 9.00),
  ('2023-05', 7.00),
  ('2023-06', 10.00),
  ('2023-07', 15.00);

环比计算

先看最终SQL及输出结果

select `month`,profit,
 lag(profit) OVER w AS 上月,
 (profit - lag(profit) OVER w) as 环比,
 100*(profit - lag(profit) OVER w)/lag(profit) OVER w as 环比比例
 from my_stat
 WINDOW w AS (ORDER BY `month`);

输出结果:

month|profit|上月|环比|环比比例
--|--|--|--|--
2022-05|10.00|NULL|NULL|NULL
2022-06|12.00|10.00|2.00|20.000000
2022-07|6.00|12.00|-6.00|-50.000000
2022-08|30.00|6.00|24.00|400.000000
2022-09|20.00|30.00|-10.00|-33.333333
2022-10|8.00|20.00|-12.00|-60.000000
2022-11|2.00|8.00|-6.00|-75.000000
2022-12|4.00|2.00|2.00|100.000000
2023-01|14.00|4.00|10.00|250.000000
2023-02|10.00|14.00|-4.00|-28.571429
2023-03|8.00|10.00|-2.00|-20.000000
2023-04|9.00|8.00|1.00|12.500000
2023-05|7.00|9.00|-2.00|-22.222222
2023-06|10.00|7.00|3.00|42.857143
2023-07|15.00|10.00|5.00|50.000000

lag

lag 函数的完整定义如下:

LAG(expr [, N[, default]]) [null_treatment] over_clause

over_clause 是必须的,它描述窗口的定义, 如上面的SQL示例最后一行:

WINDOW w AS (ORDER BY `month`);

这里定义了一个 窗口(window), 基于 month这个字段升序。

window

上一节的 over_clause 定义如下:

over_clause:
    {OVER (window_spec) | OVER window_name}

我们看到,可以 over (窗口定义) 或者  over 窗口名称。

lag(profit) OVER w AS 上月

这就是一个 over 窗口名称的示例。
接下来我们看 window_spec 的定义:

window_spec:
    [window_name] [partition_clause] [order_clause] [frame_clause]

同比环比计算

还是先看最终SQL

select `month`,profit,
 lag(profit) OVER w AS 上月,
 (profit - lag(profit) OVER w) as 环比,
 100*(profit - lag(profit) OVER w)/lag(profit) OVER w as 环比比例,
 lag(profit,12) OVER w AS 上年同月,
 (profit - lag(profit,12) OVER w) as 同比,
 100*(profit - lag(profit,12) OVER w)/lag(profit,12) OVER w as 同比比例
 from my_stat
 WINDOW w AS (ORDER BY `month`);

返回结果

monthprofit上月环比环比比例上年同月同比同比比例
2022-0510.00NULLNULLNULLNULLNULLNULL
2022-0612.0010.002.0020.000000NULLNULLNULL
2022-076.0012.00-6.00-50.000000NULLNULLNULL
2022-0830.006.0024.00400.000000NULLNULLNULL
2022-0920.0030.00-10.00-33.333333NULLNULLNULL
2022-108.0020.00-12.00-60.000000NULLNULLNULL
2022-112.008.00-6.00-75.000000NULLNULLNULL
2022-124.002.002.00100.000000NULLNULLNULL
2023-0114.004.0010.00250.000000NULLNULLNULL
2023-0210.0014.00-4.00-28.571429NULLNULLNULL
2023-038.0010.00-2.00-20.000000NULLNULLNULL
2023-049.008.001.0012.500000NULLNULLNULL
2023-057.009.00-2.00-22.22222210.00-3.00-30.000000
2023-0610.007.003.0042.85714312.00-2.00-16.666667
2023-0715.0010.005.0050.0000006.009.00150.000000

同比与环比的差别其实不大,只是 lag(profit)变成了 lag(profit,12)。 lag(profit,12)表示取前12行的数据。

需要注意的是计算同比的时候,我们需要保证数据是连续的,不然数据会有偏差,因为这里的lag(profit,12)取的是前12行的数据,如果月份数据有缺失就可以取错数据。比如:如果少了一个月,那么前12行取的可能就是去年上个月的数据了。

partition_clause 聊聊分区

我们先准备一下数据,先创建一张表 my_stat_food

CREATE TABLE `my_stat_food` (
  `month` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `profit` decimal(10,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

然后插入数据

INSERT INTO `my_stat_food` (`month`, `type`, `profit`)
VALUES
 ('2023-05', '蔬菜', 1.00),
 ('2023-05', '水果', 2.00),
 ('2023-05', '肉类', 3.00),
 ('2023-06', '蔬菜', 4.00),
 ('2023-06', '水果', 5.00),
 ('2023-06', '肉类', 6.00),
 ('2023-07', '蔬菜', 7.00),
 ('2023-07', '水果', 8.00),
 ('2023-07', '肉类', 9.00);

定义

partition_clause:
    PARTITION BY expr [, expr] ...

然后我们试试pratition的效果

select *,lag(`profit`) over (partition by `type`) as lp from my_stat_food

输出:

monthtypeprofitlp
2023-05水果2.00NULL
2023-06水果5.002.00
2023-07水果8.005.00
2023-05肉类3.00NULL
2023-06肉类6.003.00
2023-07肉类9.006.00
2023-05蔬菜1.00NULL
2023-06蔬菜4.001.00
2023-07蔬菜7.004.00

我们的数据是按月分排序的,但我们看到通过 partition进行分区后,就会分区来返回内容了。这样我们就可以通过分区来统计不同品类的环比。

问题

参考

https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html

到此这篇关于MySQL8.0实现窗口函数计算同比环比的文章就介绍到这了,更多相关MySQL 窗口函数计算内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文