Условие
Бизнес просит сделать рассылку клиентам банка с положительной кредитной историей.
Таблицы:
loans(loan_id, debtor_id, status, ...)— кредитные договоры.debtors(debtor_id, phone, name, ...)— заёмщики.sap_choice(record_id, etalon_id)— связи: одна запись клиента может иметь несколькоrecord_id, ноetalon_id— актуальные данные. Отношение etalon : records = 1 : N.uslacc(loan_id, scode, ...)— счета, связанные с кредитным договором.spracc(scode, scode_desc)— справочник видов счетов.
Часть А (простая): выборка телефонов клиентов по закрытым договорам.
Часть Б (сложнее): расширить — данные клиентов актуальные (через etalon в sap_choice) и у договора нет просрочек (сигнал — наличие в uslacc счёта определённого scode).
Часть В (тестирование): для каждой задачи продумать ошибки и составить тест-кейсы (1 для А, 3 для Б).
Решение
Часть А
SELECT DISTINCT d.phone
FROM loans l
JOIN debtors d ON d.debtor_id = l.debtor_id
WHERE l.status = 'closed';Часть Б
Шаги:
- Получить актуальные
debtor_idчерезsap_choice(resolve to etalon). - Исключить договоры с просрочками: договор не должен иметь записей в
uslaccс overdue-scode.
WITH overdue_codes AS (
SELECT scode FROM spracc WHERE scode_desc ILIKE '%просроч%'
),
loans_with_overdue AS (
SELECT DISTINCT u.loan_id
FROM uslacc u
JOIN overdue_codes oc ON oc.scode = u.scode
),
etalon AS (
SELECT record_id, etalon_id FROM sap_choice
)
SELECT DISTINCT d.phone
FROM loans l
JOIN etalon e ON e.record_id = l.debtor_id
JOIN debtors d ON d.debtor_id = e.etalon_id
WHERE l.status = 'closed'
AND l.loan_id NOT IN (SELECT loan_id FROM loans_with_overdue);Тест-кейсы
Часть А (1 тест-кейс):
- TC1: «Клиент с одним закрытым договором» — должен попасть в выборку с одним телефоном.
Часть Б (3 тест-кейса):
- TC1: Клиент с дубликатами в
debtors, актуальная запись черезsap_choice— должен возвращаться актуальный телефон. - TC2: Клиент с просрочкой по другому договору, но без просрочки по analyzed — должен попасть.
- TC3: Клиент с просрочкой по analyzed договору — НЕ должен попасть.
Доп: edge cases:
- Клиент без
sap_choice(одиночная запись). - Договор с
status = NULL. - Просроченный счёт, который уже закрыт.
Подводные камни
sap_choice1:N: один etalon на много records. Запрос должен резольвить через etalon, не наоборот.- Просрочка = «наличие счёта определённого scode». Какой именно scode — нужно понять из
spracc.scode_desc. Все scode с описанием «просрочка», «просроченный», и т.д. - Закрытие договора без полной выплаты: статус
closedможет быть «списан». Тогда это не «положительная история». Уточняйте. - Дубли телефонов: один клиент имеет несколько договоров → SELECT DISTINCT обязательно.
- Phones: формат может быть
+7...,8..., без префикса. Нормализуйте перед рассылкой. - Sentitive data: PII требует согласия на коммуникацию — фильтруйте по
subscribed_to_promo = true.
Эталонный ответ
(А) Простой JOIN loans + debtors WHERE status = 'closed'.
(Б) CTE с overdue codes, etalon resolution, NOT IN по loans_with_overdue.
(В) Test-cases на normal flow, дубликаты-resolve, просрочка по другому договору, edge cases.