Агрегирование данных в таблице по дате каждой строки в таблице - PullRequest
0 голосов
/ 22 апреля 2020

Если я выполняю следующий запрос, он приводит к строкам в 1.6M:

SELECT 
    customer_id,
    credit_id,
    date
FROM 
    wallet
WHERE
    credit_title = 'Topups'
    AND credit_type = 'Credit Card Topups'
    AND day >= DATE '2017-11-06'
    AND day <= DATE '2020-04-03'

Сейчас я пытаюсь получить для каждой строки в вышеупомянутом запросе количество и общую сумму всех кредитных операций для этого клиента до даты строки. Я пробовал приведенный ниже запрос (который является соединением с самим собой), но в результате получается 1,3 млн строк. Почему удаляются строки в соединении? credit_id является уникальным идентификатором в этой таблице.

SELECT
    customer_id,
    credit_id,
    COALESCE(COUNT(wallet_agg.credit_id), 0) AS topup_count_to_date,
    COALESCE(SUM(wallet_agg.credit_amt_usd), 0) AS topup_amount_to_date
FROM
    wallet
LEFT JOIN
    wallet AS wallet_agg
ON
    wallet.customer_id = wallet_agg.customer_id
    AND wallet_agg.date < wallet.date
WHERE
    wallet.credit_title = 'Topups'
    AND wallet.credit_type = 'Credit Card Topups'
    AND wallet.day >= DATE '2017-11-06'
    AND wallet.day <= DATE '2020-04-03'
    AND wallet_agg.credit_title = 'Topups'
    AND wallet_agg.credit_type = 'Credit Card Topups'

Вот простая демонстрация того, что я пытаюсь , которая дает ожидаемый результат. Чем отличается логика c моего более сложного запроса выше

1 Ответ

0 голосов
/ 22 апреля 2020

Ваш JOIN превращается во внутреннее соединение по условиям WHERE. Вы должны переместить условия на второй таблице в предложение ON:

FROM wallet LEFT JOIN
     wallet AS wallet_agg
     ON wallet.customer_id = wallet_agg.customer_id AND
        wallet_agg.date < wallet.date AND
        wallet_agg.credit_title = 'Topups'
        wallet_agg.credit_type = 'Credit Card Topups'
WHERE wallet.credit_title = 'Topups' AND
      wallet.credit_type = 'Credit Card Topups' AND
      wallet.day >= DATE '2017-11-06' AND
      wallet.day <= DATE '2020-04-03'

Конечно, агрегация - это слишком много для этой проблемы. Вы должны просто использовать оконные функции:

SELECT w.*
FROM (SELECT w.customer_id, w.credit_id, w.date,
             COUNT(*) OVER (PARTITION BY customer_id, credit_title, credit_type ORDER BY date) as topup_count_to_date,
             SUM(amount) OVER (PARTITION BY customer_id, credit_title, credit_type ORDER BY date) as topup_amount_to_date
      FROM wallet w
      WHERE w.credit_title = 'Topups' AND
            w.credit_type = 'Credit Card Topups' 
    ) w
WHERE w.day >= DATE '2017-11-06' AND
      w.day <= DATE '2020-04-03';
...