#sql #postgresql
Вопрос:
У меня есть данные, которые выглядят следующим образом, суммированные остатки по клиентам за определенные месяцы (сентябрь 1 2021,12:00 означает только сентябрь)
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 года по состоянию на этот пост). Общая сумма каждого ведра для данного клиента должна равняться текущему балансу.
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 долларов США, если баланс отрицательный). Кроме того, у клиентов может не быть остатков средств за предыдущий месяц (август), показанных в исходных данных, тогда это будет просто последний остаток за месяц до этого.
Как я могу эффективно выполнить это в postgresql?
Комментарии:
1. В вашем вопросе говорится, что у вас есть данные «суммированные за каждый месяц», но в образцах данных отсутствуют месяцы.
2. Спасибо, я исправил, что вижу, как это может вводить в заблуждение. Ваш ответ хорош до тех пор, пока, возможно, сначала a С выпиской переводит сальдо на последующие месяцы, когда данные отсутствуют.
Ответ №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;
Комментарии:
1. Это превосходно и очень близко. Но мне нужен дополнительный уровень предварительной обработки перед доступом к t. У исходных данных может не быть текущего баланса в сентябре, если в этом месяце у них не было никаких платежей/транзакций, как и в предыдущем месяце. Таким образом, это должно быть относительно абсолютных месяцев для каждого клиента, а не только то, какие данные доступны, т. Е. Если в месяце нет данных, он передает их в последующие месяцы вплоть до этого месяца включительно.