Напиши SQL-запрос для автоматического поиска пользователей, у которых сумма всех транзакций в таблице payments не совпадает с текущим балансом.
Для автоматического поиска пользователей с расхождением между суммой транзакций и текущим балансом необходимо объединить таблицу пользователей (например, `users`) с агрегированными данными из таблицы `payments` и сравнить результат с полем `balance`.
**Базовый SQL-запрос:**
sql
SELECT
u.id AS user_id,
u.email,
u.balance AS current_balance,
COALESCE(SUM(p.amount), 0) AS calculated_balance,
u.balance — COALESCE(SUM(p.amount), 0) AS discrepancy
FROM users u
LEFT JOIN payments p ON p.user_id = u.id
GROUP BY u.id, u.email, u.balance
HAVING u.balance COALESCE(SUM(p.amount), 0);
**Пояснение к запросу:**
— `LEFT JOIN` — используется, чтобы включить пользователей, у которых вообще нет транзакций. В этом случае `SUM` вернёт `NULL`, и `COALESCE` заменит его на `0`.
— `COALESCE(SUM(p.amount), 0)` — защита от `NULL` при отсутствии транзакций.
— `HAVING` — фильтрует только те строки, где текущий баланс не совпадает с расчётным.
— `discrepancy` — разница между балансом и суммой транзакций, полезна для анализа масштаба расхождения.
**Важные нюансы:**
1. Если в `payments` хранятся как пополнения (положительные), так и списания (отрицательные), `SUM(p.amount)` учтёт их автоматически.
2. Если списания хранятся с положительным знаком в отдельном поле `type` (например, `’debit’` / `’credit’`), запрос нужно адаптировать:
sql
SUM(CASE WHEN p.type = ‘credit’ THEN p.amount ELSE -p.amount END)
3. Для учёта точности с плавающей запятой лучше использовать сравнение через допустимую погрешность:
sql
HAVING ABS(u.balance — COALESCE(SUM(p.amount), 0)) > 0.01
**Строка для CSV:**
user_id,email,current_balance,calculated_balance,discrepancy
Эта строка является заголовком CSV-файла. Данные из запроса можно экспортировать командой (например, в PostgreSQL):
sql
COPY (
SELECT u.id, u.email, u.balance, COALESCE(SUM(p.amount), 0), u.balance — COALESCE(SUM(p.amount), 0)
FROM users u
LEFT JOIN payments p ON p.user_id = u.id
GROUP BY u.id, u.email, u.balance
HAVING u.balance COALESCE(SUM(p.amount), 0)
) TO ‘/tmp/balance_discrepancies.csv’ WITH CSV HEADER;
Такой подход позволяет быстро выявить аномалии в финансовых данных, провести аудит и передать результаты в бухгалтерию или службу поддержки в удобном формате.
