【问题标题】:mysql rolling sum cumulative serializedmysql滚动总和累积序列化
【发布时间】:2018-10-19 06:26:07
【问题描述】:

例如我有下面的表(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

比我尝试制作一个今年的报告表,如下表

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 是 EndStock 2017 年 12 月(假设 12 月的 EarlyStock 为 0),这是来自 tb_transaction 的第一个数据,而 2 月的 EarlyStock 是 EndStock 一月等等。

我期望的表是 比我尝试制作一个今年的报告表,如下表

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

公式为:

  • LivePlant = EarlyStock + 生产 - 已死
  • EndStock = LivePlant - Distri

有什么建议吗?

Here the db-fiddle for test

【问题讨论】:

  • 避免使用right join。更喜欢“标准”left join
  • 你的 MySQL 版本是多少?这是一个滚动求和问题。如果您的版本是 8.0.2 及更高版本,则可以使用Window Functions 解决
  • @MadhurBhaiya : 我的 mysql 版本是 5.6,有使用这个 mysql 版本的建议吗?
  • 是的,有一种方法可以使用会话变量。会很复杂;试一试。
  • 为什么要向我们展示两个结果集?

标签: mysql serialization cumulative-sum


【解决方案1】:

它看起来像Rolling Sum problem。使用 MySQL 8.0.2 and onwards 中的Window Functions 可以不那么冗长。但是,由于您的MySQL version is 5.6,我们可以使用User-defined Session variables 来模拟这种行为。

这项技术的基本要点是:

  • 首先,在Derived table 中,计算特定年份和月份的各种活动(如 Dead、Distributed 等)的总和值。在您的情况下,您拥有不同年份的数据,因此您仅对 Month 进行分组的方法将行不通。您需要按年和月分组。此外,仅将结果集限制为 Current year 也无济于事,因为您需要上一年 12 月份的 End stock value,才能获得下一年 1 月份的 Early stock value。
  • 现在,使用此子选择查询的结果集,并根据您的给定定义确定期末库存和早期库存。从概念上讲,它就像编写应用程序代码(例如:PHP);我们使用上一行的 End stock 值作为当前行的 Early stock。最后,将期末库存值设置为当前行的期末库存(后计算)。
  • 现在,因为您不想要与上一年对应的行;我建议您可以忽略应用程序代码中的该行。如果您只想在查询中处理它;那么您将不得不再次将完整的结果集作为派生表,并使用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  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 2021-06-08
    • 1970-01-01
    • 2019-02-15
    • 2018-07-02
    相关资源
    最近更新 更多