如何在几个月前使用 SQL 获得运行平衡的差异?

Posted

技术标签:

【中文标题】如何在几个月前使用 SQL 获得运行平衡的差异?【英文标题】:How to get difference in running balance using SQL by months prior? 【发布时间】:2021-09-11 00:26:14 【问题描述】:

我的数据如下所示,是客户在某些月份(2021 年 9 月 12 日凌晨 12:00 仅表示 9 月)的总余额

client_id|balance_month|running_balance
20|September 1,2021,12:00 AM|$1000.00
20|August 1,2021,12:00 AM|$900.00
20|July 1,2021,12:00 AM|$600.00
20|April 1,2021,12:00 AM|$400.00
10|September 1,2021,12:00 AM|-$500.00
10|August 1,2021,12:00 AM|$900.00
10|July 1,2021,12:00 AM|$600.00
10|April 1,2021,12:00 AM|$400.00

我想获取每个客户的最新余额,并查看与上个月、两个月前、三个月前和四个多月前的差异。 (截至本文的 2021 年 9 月)。给定客户端的每个存储桶的总和应等于当前余额。

client_id|0to30|30to60|60to90|90to120|120plus
20       |$100 |$300  |$200  |$0     |$400
10       |$0   |$0    |$0    |$0     |$0

这样,每个客户的分箱总额(100 美元+300 美元+200 美元+0 美元+400 美元)加起来就是当前的未结余额(1000 美元,如果余额为负数,则为 0 美元)。此外,客户可能没有原始数据中显示的上个月(8月)的余额,那么它只是之前一个月的最后一个余额。

如何在 postgresql 中有效地完成此任务?

【问题讨论】:

您的问题说您有“每月汇总”的数据,但样本数据缺少月份。 谢谢我更正了,我知道这可能会产生误导。你的答案是好的,只要首先一个 WITH 语句在数据不存在时将余额前馈到随后的月份。 【参考方案1】:

您可以倒数月份并使用条件聚合:

select client_id,
       (max(running_balance) filter (where seqnum = 1)  -
        max(running_balance) filter (where seqnum = 2)
       ) as month_1,
       (max(running_balance) filter (where seqnum = 2)  -
        max(running_balance) filter (where seqnum = 3)
       ) as month_2,
       (max(running_balance) filter (where seqnum = 3)  -
        max(running_balance) filter (where seqnum = 4)
       ) as month_3,
       max(running_balance) filter (where seqnum = 4) as month_4
from (select t.*,
             row_number() over (partition by client_id order by balance_month desc) as seqnum
      from t
     ) t
group by client_id;

注意:如果您想要明确的月份,则只需使用 filter 中的月份:

select client_id,
       (max(running_balance) filter (where balance_month::date = '2021-09-01')  -
        max(running_balance) filter (where balance_month::date = '2021-08-01')
       ) as month_1,
       (max(running_balance) filter (where balance_month::date = '2021-08-01')  -
        max(running_balance) filter (where balance_month::date = '2021-07-01')
       ) as month_2,
       (max(running_balance) filter (where balance_month::date = '2021-07-01')  -
        max(running_balance) filter (where balance_month::date = '2021-06-01')
       ) as month_3,
       max(running_balance) filter (where balance_month::date = '2021-06-01') as month_4
from t
group by client_id;

【讨论】:

这非常好,非常接近。但是在访问 t 之前我需要额外的预处理层。如果原始数据在 9 月份没有任何付款/交易,则可能在 9 月份没有当前余额,与前一个月相同。因此,这需要与每个客户的绝对月份相关,而不仅仅是可用的数据,即如果一个月没有数据,它会将其转发到随后的几个月,包括本月。

以上是关于如何在几个月前使用 SQL 获得运行平衡的差异?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:如何在几秒钟内获得两个时间戳之间的差异

比较不同编码的文件

耗时几个月,终于找到了JVM停顿十几秒的原因

Magento / Paypal 预留资金在几个月后收取

如何处理取消的定期付款

如何计算3个月前的到期日期将到期