Отладка SQL-запросов ⌛️ Большую часть времени аналитики пишут скрипты в определённой СУБД: достают оттуда данные для моделей, отчётности, выгрузок, продуктовых исследований и прочих задач. Предположим, ты начал строить большую витрину, которая должна покрывать бизнес-потребности.
Всё идёт нормально, но вдруг: 1. Нет записей, хотя должны быть / записей стало меньше
2. Данные задвоились
3. Результаты не сходятся с дашбордом / другой внутренней системой (например, в 1С / сервисе заказов и тд)
Этот пост - про быструю и понятную отладку SQL-запросов, особенно если он уже раздулся на тысячи строк. 1️⃣ Начало с верхнеуровневой структуры Если в коде есть подзапросы, лучше переписать их на CTE / временные таблицы. Так код легче читать и отлаживать по шагам.
Простой подзапрос: `select ... from ( select ... from orders where ... ) t join ...
CTE: `with filtered_orders AS ( select ... from orders where ... ) select ... from filtered_orders join ...
Стало чуточку проще читать + можно проверить, что в filtered_orders, следующий шаг про это
2️⃣ Проверка CTE или временных таблиц
Здесь мы проверяем количество строк / уникальных сущностей по типу order_id / user_id, проверяем на пустые значения
`select count(*) as total_rows, count(distinct user_id) as unique_users from filtered_orders;
3️⃣ Спускаемся глубже, смотрим с какого момента началась проблема (идем внутрь запроса) Что нас ждет внутри? Джойны / оконные функции / группировки.
Хорошая практика - это посмотреть, задублировались ли ключи, по которым будет в дальнейшем JOIN
`select o.order_id, count() as cnt from orders o join transactions t on o.order_id = t.order_id group by o.order_id having count() > 1;
Если дублируется, то надо ответить на вопрос: ожидаемое это поведение или нет? Если проблема, то следующий шаг.
4️⃣ Контроль за дублями
Базовая проблема: в одной таблице ключ уникален, в другом нет (можно, например, предагрегировать, используя row_number() / distinct / group by
`with transaction_agg as ( select order_id, sum(amount) as total_amount from transactions group by order_id ) select o.order_id, t.total_amount from orders o left join transaction_agg as t ON o.order_id = t.order_id;
А если так нельзя схлопнуть, можно атрибуцировать за какой-то промежуток времени и связывать по дню, например
5️⃣Хорошая и простая практика: посмотреть глазами Берем значение ключа, по которому связываем и смотрим, как дублируется, из-за чего. Возможно, на транзакции приходится несколько записей с типом оплаты (и это надо предусмотреть)
`select * from orders o join transactions t on o.order_id = t.order_id where o.order_id = 'abc123';
6️⃣Последнее Действительно я понимаю данные, которые используются при сборе витрины?
Бывают разные сущности, но хочется понимать как мы закрываем бизнес-задачу, используя именно ЭТИ данные (тут про смысл аналитического мышления / бизнес-смысла и смысла данных
Понравился формат поста? Ставьте 🔥, пишите комментарии, какие пункты еще стоит добавить``````