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:

有什么建议吗?

Here the db-fiddle for test

看起来像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