mysql 滚动总和累计连载
mysql rolling sum cumulative serialized
例如我有波纹管 table (tb_transaction)
id_trans date_trans production_plant dead_plant distribution_plant
25 2017-12-31 1000 100 200
26 2018-01-17 150 0 0
27 2018-02-07 0 50 100
28 2018-03-07 250 0 75
29 2018-05-10 500 50 0
然后我尝试为今年做一份报告 table,如下所示 table
month EarlyStock production dead LivePlant Distri EndStock
January 150 0 150 0 150
February 0 50 -50 100 -150
March 250 0 250 75 175
April 0 0 0 0 0
May 500 50 450 0 450
June 0 0 0 0 0
July 0 0 0 0 0
August 0 0 0 0 0
September 0 0 0 0 0
October 0 0 0 0 0
November 0 0 0 0 0
December 0 0 0 0 0
1 月的 EarlyStock 是 2017 年 12 月的 EndStock(假设 12 月的 EarlyStock 为 0)这是来自 tb_transaction 的第一个数据,而 2 月的 EarlyStock 是 EndStock 1 月,依此类推。
我的预期 table 是
然后我尝试为今年做一份报告 table,如下所示 table
month EarlyStock production dead LivePlant Distri EndStock
January 700 150 0 850 0 850
February 850 0 50 800 100 700
March 700 250 0 950 75 875
April 875 0 0 875 0 875
May 875 500 50 1325 0 1325
June 0 0 0 0 0
July 0 0 0 0 0
August 0 0 0 0 0
September 0 0 0 0 0
October 0 0 0 0 0
November 0 0 0 0 0
December 0 0 0 0 0
Formula is:
- LivePlant = EarlyStock + 生产 - 停产
- EndStock = LivePlant - Distri
有什么建议吗?
看起来像Rolling Sum problem. It is doable in less verbose manner using Window Functions in MySQL 8.0.2 and onwards. But, since your , we can emulate this behavior using User-defined Session variables。
这项技术的基本要点是:
- 首先,在 Derived table 中,计算 特定年份和月份 的各种活动(如 Dead、Distributed 等)的总和值。在你的情况下,你有不同年份的数据,所以你单独对 Month 进行分组的方法是行不通的。您需要对年份和月份进行分组。此外,仅将结果集限制为当年也无济于事,因为您需要上一年 12 月的期末库存值,才能获得下一年 1 月的早期库存值。
- 现在,使用此子select 查询的结果集,并根据您给定的定义确定 End Stock 和 Early Stock。从概念上讲,这就像编写应用程序代码(例如:PHP);我们使用前一行的 End stock 值作为当前行的 Early stock。最后,将 End stock 值设置为当前行的 End stock(post 计算)。
- 现在,因为您不想要对应于上一年的行;我建议您可以在应用程序代码中忽略该行。不过,如果您只想在查询中处理它;那么您将不得不再次将完整的结果集作为 Derived table,并使用
Where
过滤掉除当前年份以外的年份中的行。
尝试以下代码 (DB Fiddle DEMO):
SELECT t1.year_no,
t1.month_name,
@early := @endst AS EarlyStock,
@prod := t1.production AS production,
@dead := t1.dead AS dead,
( @early + @prod - @dead ) AS LivePlant,
@dist := t1.distri AS Distri,
@endst := ( @early + @prod - @dead - @dist ) AS EndStock
FROM (SELECT Coalesce(Year(trans.date_trans), Year(CURRENT_DATE())) AS year_no,
Coalesce(Month(trans.date_trans), mon.id_month) AS month_no,
mon.month_name,
Coalesce(Sum(trans.production_plant), 0) AS production,
Coalesce(Sum(trans.dead_plant), 0) AS dead,
Coalesce(Sum(trans.distribution_plant), 0) AS Distri
FROM tb_month AS mon
LEFT JOIN tb_transaction AS trans
ON Month(trans.date_trans) = mon.id_month
GROUP BY year_no,
month_no,
mon.month_name
ORDER BY year_no,
month_no) AS t1
CROSS JOIN (SELECT @prod := 0,
@dead := 0,
@dist := 0,
@early := 0,
@endst := 0) AS user_init_vars
例如我有波纹管 table (tb_transaction)
id_trans date_trans production_plant dead_plant distribution_plant
25 2017-12-31 1000 100 200
26 2018-01-17 150 0 0
27 2018-02-07 0 50 100
28 2018-03-07 250 0 75
29 2018-05-10 500 50 0
然后我尝试为今年做一份报告 table,如下所示 table
month EarlyStock production dead LivePlant Distri EndStock
January 150 0 150 0 150
February 0 50 -50 100 -150
March 250 0 250 75 175
April 0 0 0 0 0
May 500 50 450 0 450
June 0 0 0 0 0
July 0 0 0 0 0
August 0 0 0 0 0
September 0 0 0 0 0
October 0 0 0 0 0
November 0 0 0 0 0
December 0 0 0 0 0
1 月的 EarlyStock 是 2017 年 12 月的 EndStock(假设 12 月的 EarlyStock 为 0)这是来自 tb_transaction 的第一个数据,而 2 月的 EarlyStock 是 EndStock 1 月,依此类推。
我的预期 table 是 然后我尝试为今年做一份报告 table,如下所示 table
month EarlyStock production dead LivePlant Distri EndStock
January 700 150 0 850 0 850
February 850 0 50 800 100 700
March 700 250 0 950 75 875
April 875 0 0 875 0 875
May 875 500 50 1325 0 1325
June 0 0 0 0 0
July 0 0 0 0 0
August 0 0 0 0 0
September 0 0 0 0 0
October 0 0 0 0 0
November 0 0 0 0 0
December 0 0 0 0 0
Formula is:
- LivePlant = EarlyStock + 生产 - 停产
- EndStock = LivePlant - Distri
有什么建议吗?
看起来像Rolling Sum problem. It is doable in less verbose manner using Window Functions in MySQL 8.0.2 and onwards. But, since your
这项技术的基本要点是:
- 首先,在 Derived table 中,计算 特定年份和月份 的各种活动(如 Dead、Distributed 等)的总和值。在你的情况下,你有不同年份的数据,所以你单独对 Month 进行分组的方法是行不通的。您需要对年份和月份进行分组。此外,仅将结果集限制为当年也无济于事,因为您需要上一年 12 月的期末库存值,才能获得下一年 1 月的早期库存值。
- 现在,使用此子select 查询的结果集,并根据您给定的定义确定 End Stock 和 Early Stock。从概念上讲,这就像编写应用程序代码(例如:PHP);我们使用前一行的 End stock 值作为当前行的 Early stock。最后,将 End stock 值设置为当前行的 End stock(post 计算)。
- 现在,因为您不想要对应于上一年的行;我建议您可以在应用程序代码中忽略该行。不过,如果您只想在查询中处理它;那么您将不得不再次将完整的结果集作为 Derived table,并使用
Where
过滤掉除当前年份以外的年份中的行。
尝试以下代码 (DB Fiddle DEMO):
SELECT t1.year_no,
t1.month_name,
@early := @endst AS EarlyStock,
@prod := t1.production AS production,
@dead := t1.dead AS dead,
( @early + @prod - @dead ) AS LivePlant,
@dist := t1.distri AS Distri,
@endst := ( @early + @prod - @dead - @dist ) AS EndStock
FROM (SELECT Coalesce(Year(trans.date_trans), Year(CURRENT_DATE())) AS year_no,
Coalesce(Month(trans.date_trans), mon.id_month) AS month_no,
mon.month_name,
Coalesce(Sum(trans.production_plant), 0) AS production,
Coalesce(Sum(trans.dead_plant), 0) AS dead,
Coalesce(Sum(trans.distribution_plant), 0) AS Distri
FROM tb_month AS mon
LEFT JOIN tb_transaction AS trans
ON Month(trans.date_trans) = mon.id_month
GROUP BY year_no,
month_no,
mon.month_name
ORDER BY year_no,
month_no) AS t1
CROSS JOIN (SELECT @prod := 0,
@dead := 0,
@dist := 0,
@early := 0,
@endst := 0) AS user_init_vars