Условие
Дано две таблицы. Клиенты — справочник клиентов и их счетов (одна строка на пару клиент-счёт), Cчета — история состояний счёта на конкретные даты.
create table #Клиенты (
client_id varchar(1),
FIO varchar(255),
Region varchar(50),
account_num int
);
create table #Cчета (
[Date] date,
Summa_USD money,
Account_num int
);Нужно отобрать клиентов из г. Москва с суммарным остатком по всем счетам клиента ≥ 20 000 на последнюю доступную дату.
Тестовые данные
| client_id | FIO | Region | account_num |
|---|---|---|---|
| A | Иванов | Москва | 111 |
| A | Иванов | Москва | 222 |
| B | Петров | Иваново | 333 |
| C | Сидоров | Москва | 444 |
| Date | Summa_USD | Account_num |
|---|---|---|
| 2012-01-01 | 15000 | 111 |
| 2012-02-01 | 10000 | 111 |
| 2012-02-01 | 5000 | 222 |
| 2012-03-01 | 30000 | 333 |
| 2012-04-01 | 20000 | 444 |
Решение
Подход
«Последняя доступная дата» в задании двусмысленна: это max(date) по счёту или по всей таблице? Разумная интерпретация — по каждому счёту берём последний снимок, потом суммируем по клиенту.
Реализация
WITH last_balance AS (
-- Последний снимок по каждому счёту
SELECT
Account_num,
Summa_USD,
ROW_NUMBER() OVER (PARTITION BY Account_num ORDER BY [Date] DESC) AS rn
FROM #Cчета
),
client_total AS (
SELECT
k.client_id,
MAX(k.FIO) AS FIO,
SUM(b.Summa_USD) AS total_balance
FROM #Клиенты k
JOIN last_balance b ON b.Account_num = k.account_num AND b.rn = 1
WHERE k.Region = 'Москва'
GROUP BY k.client_id
)
SELECT client_id, FIO, total_balance
FROM client_total
WHERE total_balance >= 20000;Проверка
- Иванов (Москва): счёт 111 — последний остаток 10 000 (за февраль), счёт 222 — 5 000. Сумма = 15 000. Не проходит.
- Сидоров (Москва): счёт 444 — 20 000. Проходит.
- Петров (Иваново) — отбрасывается по региону.
Ответ: C, Сидоров, 20000.
Подводные камни
- Что такое «последняя дата». Глобальный
max(date)по таблице может относиться вообще к другому счёту, и для счёта 111 пришлось бы взять остаток 0 (нет записи). У задачи нужно явно проговорить интерпретацию. - Дубль клиента. Один
client_idвстречается с разнымиaccount_num— нельзя сравниватьSumma_USDкаждой строки с 20 000 поодиночке, нужна сумма по клиенту. - Region может содержать пробелы / разный регистр —
WHERE Region = 'Москва'строгое равенство; в проде лучшеLOWER(TRIM(Region)) = 'москва'. HAVINGvs подзапрос. Можно сразуSELECT ... FROM ... GROUP BY client_id HAVING SUM(...) >= 20000, но «последний остаток» требует оконки.
Эталонный ответ
CTE с ROW_NUMBER() OVER (PARTITION BY Account_num ORDER BY Date DESC) для последнего снимка → JOIN с клиентами, фильтр по Москве → агрегат SUM по клиенту → фильтр >= 20000.