Отладка 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️⃣Последнее Действительно я понимаю данные, которые используются при сборе витрины?

Бывают разные сущности, но хочется понимать как мы закрываем бизнес-задачу, используя именно ЭТИ данные (тут про смысл аналитического мышления / бизнес-смысла и смысла данных

Понравился формат поста? Ставьте 🔥, пишите комментарии, какие пункты еще стоит добавить``````