SQL:获取上个月的绝对亏损和百分比

时间:2020-01-26 20:31:42

标签: mysql sql window

id | year | month | category | value
1    2019    01      apple       3
1    2018    12      apple       2
1    2019    01      carrot      4

在此示例中,预期结果是:

category | last month | gain or loss % | gain or loss
 apple       2019-01         +50%              +1
 carrot      2019-01         +100%             +4       // Note: no carrot value on previous month

是否有任何方法可以执行此操作而无需进行任何昂贵的连接?

2 个答案:

答案 0 :(得分:0)

如果运行的是MySQL 8.0,则可以使用窗口函数和聚合:

select 
    category,
    max(case when rn = 1 then concat(year, '-', month)) last_month,
    coalesce(
        (
            max(case when rn = 1 then value end) 
            - max(case when rn = 2 then value end)
        ) 
        / max(case when rn = 2 then value end), 
    1) gain_or_loss_ratio,
    max(case when rn = 1 then value end) 
        - coalesce(max(case when rn = 2 then value end), 0) gain_or_loss
from (
    select
        t.*,
        row_number() over(partition by category order by year desc, month desc) rn
    from mytable t
) t
where rn in (1, 2)
group by category

这使您可以比较每个类别的最后2个值,这就是我对您的问题的理解方式。第三列包含一个介于0到1之间的值,而不是一个百分比,我发现它更有用(您可以在应用程序端根据需要设置其格式)。

您可以通过添加一级嵌套来缩短算术表达式,如下所示:

select
    category,
    last_month,
    coalesce((last_value1 - last_value2) / last_value2, 1) gain_or_loss_ratio,
    last_value1 - coalesce(last_value2, 0) gain_or_loss
from (
    select 
        category,
        max(case when rn = 1 then concat(year, '-', month)) last_month,
        max(case when rn = 1 then value end) last_value1,
        max(case when rn = 2 then value end) last_value2
    from (
        select
            t.*,
            row_number() over(partition by category order by year desc, month desc) rn
        from mytable t
    ) t
    where rn in (1, 2)
    group by category
) t

答案 1 :(得分:0)

如果您没有中间月份缺失的情况,那么一个简单的滞后工作(以及一些过滤):

public class myClass{
    public static string networkHandler(string s) { //static method
         try {
           string ss = s;
         }
         catch(string s) {
           //handle error
         }
    }
}

如果您特别想在数据中指定最近的月份而不指定它,也可以使用select category, concat_ws('-', year, month), coalesce(val / prev_value, 1) as gain_loss_rate, (val - coalesce(prev_value, 0)) as gain_or_loss from (select t.*, lag(value) over (partition by id, category order by year, month) as prev_value from t ) t where year = 2019 and month = '01';

rank()