【问题标题】:Get growth rate per month from transaction table从交易表中获取每月的增长率
【发布时间】:2021-08-23 17:26:15
【问题描述】:

我有这样的交易记录:

date revenue balance
2021-05-03 0 1000
2021-05-21 500 1500
2021-05-23 -250 1250
2021-06-02 -500 750

我想得到这样的结果:

date growth
2021-5 0.25
2021-6 -0.4

公式为: 余额(月末)-余额(月初)/余额(月初)

例如:1250-1000/1000=0.25

和:750-1250/1250=-0.4

我非常感谢一个尽可能简单的 MYSQL 查询提示。

【问题讨论】:

    标签: mysql sql mysql-5.7


    【解决方案1】:

    此计算的逻辑与您的示例不一致。

    我们以“月初”和“月末”为当月第一个日期的记录和当月最后一个日期的记录。

    通过这个计算,你确实在 05 月得到了“0.25”,但是对于 06 月,只有一条记录,所以它是当月的第一条和最后一条记录,计算为 (750-750) /750,即为零。

    在您的示例计算中,您使用上个月末来计算第 06 个月的值,但使用第 05 个月的结束和开始来计算第 05 个月的增长。这是两种不同的计算方式!您必须决定使用哪一个。

    如果你想使用给定月份的第一条和最后一条记录(就像你在第 05 个月所做的那样),你可以使用这个:

    SELECT 
      `t0`.`month`,
      IF(`t1`.balance = 0,
        NULL,
        ((`t2`.balance - `t1`.balance) / `t1`.balance)) AS `growth`
    FROM
      (SELECT 
        DATE_FORMAT(`date`, '%Y-%m') AS 'month',
            MIN(`date`) AS 'min_date',
            MAX(`date`) AS 'max_date'
      FROM
        `your_table`
      GROUP BY MONTH(`date`)) AS `t0`
    JOIN
      `your_table` AS `t1` ON (`t1`.date = `min_date`)
    JOIN
      `your_table` AS `t2` ON (`t2`.date = `max_date`);
    

    请注意“IF”,因为您必须防止除以零 - 从零到任何正值的增长始终是“无穷大百分比”,这没有任何意义 - 所以您必须知道您的事情在这些情况下,重新尝试构建应该可以工作。

    【讨论】:

    • 你说的选择当月第一天的余额或者上个月最后一天的余额是正确的。但是,为了得到当月的初始余额,必须减去第一天的收入。 (可以在我的单独帖子中看到)。
    【解决方案2】:

    假设DB版本为8.0,则可以使用解析函数,如下查询

    SELECT month,
           (bal_end - COALESCE(LAG(bal_end) OVER(ORDER BY month), bal_start)) /
           COALESCE(LAG(bal_end) OVER(ORDER BY month), bal_start) AS growth
      FROM (SELECT month,
                   MAX(CASE
                         WHEN m_end = 1 THEN
                          sum_balance
                       END) AS bal_end,
                   MAX(CASE
                         WHEN m_start = 1 THEN
                          sum_balance
                       END) bal_start
              FROM (SELECT month,
                           SUM(COALESCE(CASE
                                          WHEN bal_start = 1 THEN
                                           balance
                                        END,
                                        0) + COALESCE(revenue, 0)) OVER(ORDER BY date) AS sum_balance,
                           m_end,
                           m_start,
                           date
                      FROM (SELECT DATE_FORMAT(date, '%Y-%m') AS month,
                                   t.*,
                                   ROW_NUMBER() OVER(PARTITION BY DATE_FORMAT(date, '%Y-%m') ORDER BY date) AS m_start,
                                   ROW_NUMBER() OVER(PARTITION BY DATE_FORMAT(date, '%Y-%m') ORDER BY date DESC) AS m_end,
                                   ROW_NUMBER() OVER(ORDER BY date) AS bal_start
                              FROM t) AS t0) AS t1
             GROUP BY month) AS t2;
    
    month growth
    2021-05 0.2500
    2021-06 -0.4000

    Demo

    【讨论】:

    • 感谢您的回答。不幸的是,我忘了提到它应该适用于 MYSQL 5...我的错误
    【解决方案3】:

    您需要提取上个月的余额(如果存在)。为此,您可以将lag() 与条件聚合结合使用:

    select year(date), month(date),
           (-1 +
            (max(case when seqnum_desc = 1 then balance end) /
             max(case when seqnum_asc = 1 then coalesce(prev_balance, balance) end)
            )
           ) as growth
    from (select t.*,
                 row_number() over (partition by year(date), month(date) order by date) as seqnum_asc,
                 row_number() over (partition by year(date), month(date) order by date desc) as seqnum_desc,
                 lag(balance) over (order by date) as prev_balance
          from t
         ) t
    group by year(date), month(date);
    

    Here 是一个 dbfiddle。

    【讨论】:

    • @BarbarosÖzhan 。 . .谢谢你。我回答错了问题。我完全改变了答案。
    • 感谢您的回答。不幸的是,我忘了提到它应该适用于 MYSQL 5...我的错误
    【解决方案4】:

    @MBauerDC ...谢谢。就我而言,这是我使用 MYSQL 5.7 时的正确方向。但是,要获得最终结果,仍然需要进行一些更改:

    SELECT 
      t0.month,
      (t2.balance - (t1.balance - t1.revenue)) / (t1.balance - t1.revenue) AS growth
    FROM
      (SELECT 
        DATE_FORMAT(date, '%Y-%m') AS 'month',
            MIN(date) AS 'min_date',
            MAX(date) AS 'max_date'
      FROM
        t
      GROUP BY month) AS t0
    JOIN
      t AS t1 ON (t1.date = min_date)
    JOIN
      t AS t2 ON (t2.date = max_date)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      • 2011-09-10
      相关资源
      最近更新 更多