← Назад к вопросам

SQL: Изменение в капитале при переводах между аккаунтами

1.7 Middle🔥 111 комментариев
#SQL и базы данных#Аналитика и метрики

Условие

Дана таблица транзакций переводов между аккаунтами:

CREATE TABLE transactions (
    transaction_id INT PRIMARY KEY,
    sender_id INT,
    receiver_id INT,
    amount DECIMAL(10,2),
    transaction_date DATE
);

Пример данных:

transaction_idsender_idreceiver_idamounttransaction_date
1100200500.002024-01-15
2200300300.002024-01-16
3300100200.002024-01-17
4100300150.002024-01-18

Задание:

  1. Рассчитайте итоговое изменение баланса для каждого аккаунта (отправленное минус полученное)
  2. Найдите аккаунты с положительным и отрицательным балансом изменений
  3. Определите пару аккаунтов с максимальным объёмом переводов между собой

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Задача и подход

Нужно анализировать переводы между аккаунтами: рассчитать изменение баланса, определить положительные/отрицательные балансы и найти наиболее активные пары аккаунтов.

Шаг 1: Изменение баланса для каждого аккаунта

WITH account_cash_flow AS (
    SELECT 
        account_id,
        SUM(CASE WHEN flow_type = 'sent' THEN amount ELSE 0 END) AS total_sent,
        SUM(CASE WHEN flow_type = 'received' THEN amount ELSE 0 END) AS total_received
    FROM (
        SELECT sender_id AS account_id, amount, 'sent' AS flow_type 
        FROM transactions
        UNION ALL
        SELECT receiver_id, amount, 'received' 
        FROM transactions
    ) flows
    GROUP BY account_id
)
SELECT 
    account_id,
    total_sent,
    total_received,
    total_sent - total_received AS balance_change
FROM account_cash_flow
ORDER BY balance_change DESC;

Результат: 100: -350, 200: +200, 300: +150

Шаг 2: Классификация на положительные и отрицательные

WITH balance_data AS (
    SELECT 
        account_id,
        SUM(CASE WHEN flow_type = 'sent' THEN amount ELSE 0 END) -
        SUM(CASE WHEN flow_type = 'received' THEN amount ELSE 0 END) AS balance
    FROM (
        SELECT sender_id AS account_id, amount, 'sent' FROM transactions
        UNION ALL
        SELECT receiver_id, amount, 'received' FROM transactions
    ) flows
    GROUP BY account_id
)
SELECT 
    account_id,
    balance,
    CASE WHEN balance > 0 THEN 'Negative' ELSE 'Positive' END AS balance_type
FROM balance_data
ORDER BY balance DESC;

Шаг 3: Пара аккаунтов с максимальным объёмом

SELECT 
    LEAST(sender_id, receiver_id) AS account_a,
    GREATEST(sender_id, receiver_id) AS account_b,
    SUM(amount) AS total_volume
FROM transactions
GROUP BY 
    LEAST(sender_id, receiver_id),
    GREATEST(sender_id, receiver_id)
ORDER BY total_volume DESC
LIMIT 1;

Для примера: пара (100, 300) с объёмом 350 (100→300: 150, 300→100: 200)

Объяснение логики

Шаг 1: UNION объединяет отправки и получения как потоки денежных средств, затем группируем по account_id.

Шаг 2: Положительный баланс означает, что счёт получил больше, чем отправил. Отрицательный — отправил больше.

Шаг 3: LEAST/GREATEST нормализуют пары (100,200) и (200,100) в одну запись для правильной агрегации.

SQL: Изменение в капитале при переводах между аккаунтами | PrepBro