🧠 Airflow и Pandas — мощная связка для аналитика.
В этом DAG мы качаем данные из API, обрабатываем в Pandas и сохраняем в Excel.
Расписание, логи, структура raw → processed, типизация и надёжность.
Идеальный шаблон для автоматизации отчётов, парсинга и ETL.
💸 Поддержать канал
👉 Senior Data Analyst | #python
В этом DAG мы качаем данные из API, обрабатываем в Pandas и сохраняем в Excel.
Расписание, логи, структура raw → processed, типизация и надёжность.
Идеальный шаблон для автоматизации отчётов, парсинга и ETL.
💸 Поддержать канал
👉 Senior Data Analyst | #python
🔥4👍3
Зачем вообще DAG для Pandas?
У каждого аналитика есть «та самая папка со скриптами».
API, Excel, выгрузки, подсчёты, пересчёты — всё вручную. Потом через cron. Но если честно — пора переходить на DAG.
Этот пример показывает, как из ручного ETL сделать стабильный, управляемый и приятный пайплайн, который:
• выполняется по расписанию
• логирует каждый шаг
• сохраняет результат по структуре
• валится с ошибкой, если что-то пошло не так
• и вообще выглядит по-взрослому
Как устроен код?
1️⃣ fetch_data
Качает данные из
→ Превращает JSON в
→ Сохраняет как
→ Использует дату из контекста
2️⃣ process_data
→ Читает
→ Сохраняет результат в
→ Демонстрирует, как можно обрабатывать данные Pandas внутри DAG
3️⃣ DAG
→ Запускается ежедневно (
→ Использует
→ Передаёт дату через контекст (магия, но понятная)
▪️ Структура данных выглядит вот так:
Чёткое разделение на raw и processed
Можно вернуться к исходнику, пересчитать, проверить. Красота.
▪️Почему это лучше, чем просто скрипт fetch_and_process.py?
Ну смотри, что ты получаешь с Airflow:
• Ретрай, если API временно отвалился
• Контроль за успехом выполнения
• Отправку алёртов, если что-то пошло не так
• Удобный UI — наглядно видно, что работает, а что нет
• Логи — по каждому шагу, с ошибками, stacktrace и временем
И всё это — автоматически. Просто потому что ты перешёл от «файлика» к DAG.
▪️Как адаптировать под свои задачи?
Airflow гибкий. Меняешь куски — и вуаля:
• вместо Excel → пишем в ClickHouse, PostgreSQL или в облако
• вместо API → читаем Google Sheets, S3, базы
• вместо Pandas → ставим Polars или SQLAlchemy
DAG — это про структуру.
▪️А что насчёт прикладной аналитики?
Вот реальные кейсы:
• Парсинг прайс-листов → автоматическая сводка изменений
• Проверка API магазинов → алёрт, если скидки исчезли
• Сводка по REST-запросам → Excel-отчёт или сообщение в мессенджер
Всё, что раньше делалось вручную — теперь живёт в пайплайне. И ты не вспоминаешь про него, пока не придёт алёрт.
▪️Главный вывод
Airflow — это не только для big data и дата-инженеров.
Это про предсказуемость, контроль.
Если ты один раз скачал и обработал файл — да, это скрипт.
Но если ты делаешь это каждый день — это уже DAG. И его пора так оформить.
💥 Как тебе ?
🔥 — узнал(а) что-то новое
🤝 — темы хорошо знакомы
💸 Поддержать канал
👉 Senior Data Analyst | #python
У каждого аналитика есть «та самая папка со скриптами».
API, Excel, выгрузки, подсчёты, пересчёты — всё вручную. Потом через cron. Но если честно — пора переходить на DAG.
Этот пример показывает, как из ручного ETL сделать стабильный, управляемый и приятный пайплайн, который:
• выполняется по расписанию
• логирует каждый шаг
• сохраняет результат по структуре
• валится с ошибкой, если что-то пошло не так
• и вообще выглядит по-взрослому
Как устроен код?
1️⃣ fetch_data
Качает данные из
https://dummyjson.com/products
→ Превращает JSON в
pandas.DataFrame
→ Сохраняет как
data/raw/products_<ds>.csv
→ Использует дату из контекста
(context["ds"])
— то есть работает "по календарю"2️⃣ process_data
→ Читает
csv
, считает price_with_tax
→ Сохраняет результат в
data/processed/products_cleaned_<ds>.xlsx
→ Демонстрирует, как можно обрабатывать данные Pandas внутри DAG
3️⃣ DAG
→ Запускается ежедневно (
@daily
)→ Использует
PythonOperator
→ Передаёт дату через контекст (магия, но понятная)
▪️ Структура данных выглядит вот так:
/opt/airflow/data/
├── raw/
│ └── products_2025-07-22.csv
└── processed/
└── products_cleaned_2025-07-22.xlsx
Чёткое разделение на raw и processed
Можно вернуться к исходнику, пересчитать, проверить. Красота.
▪️Почему это лучше, чем просто скрипт fetch_and_process.py?
Ну смотри, что ты получаешь с Airflow:
• Ретрай, если API временно отвалился
• Контроль за успехом выполнения
• Отправку алёртов, если что-то пошло не так
• Удобный UI — наглядно видно, что работает, а что нет
• Логи — по каждому шагу, с ошибками, stacktrace и временем
И всё это — автоматически. Просто потому что ты перешёл от «файлика» к DAG.
▪️Как адаптировать под свои задачи?
Airflow гибкий. Меняешь куски — и вуаля:
• вместо Excel → пишем в ClickHouse, PostgreSQL или в облако
• вместо API → читаем Google Sheets, S3, базы
• вместо Pandas → ставим Polars или SQLAlchemy
DAG — это про структуру.
▪️А что насчёт прикладной аналитики?
Вот реальные кейсы:
• Парсинг прайс-листов → автоматическая сводка изменений
• Проверка API магазинов → алёрт, если скидки исчезли
• Сводка по REST-запросам → Excel-отчёт или сообщение в мессенджер
Всё, что раньше делалось вручную — теперь живёт в пайплайне. И ты не вспоминаешь про него, пока не придёт алёрт.
▪️Главный вывод
Airflow — это не только для big data и дата-инженеров.
Это про предсказуемость, контроль.
Если ты один раз скачал и обработал файл — да, это скрипт.
Но если ты делаешь это каждый день — это уже DAG. И его пора так оформить.
💥 Как тебе ?
🔥 — узнал(а) что-то новое
🤝 — темы хорошо знакомы
💸 Поддержать канал
👉 Senior Data Analyst | #python
🔥11
🧠 Python для аналитиков: if, elif, else — без боли
Когда «управление логикой» звучит не как философия, а как реальный навык
Это первая серия модуля 3 — и она про то, как писать условия, не превращаясь в программиста 2008 года.
Что внутри:
→ на пальцах объясняем, как работает
→ практическое задание: определяем возрастную категорию
→ советы и фейлы: как не закопаться в условиях и не получить
→ реальный кейс: расчёт налога по типу дохода, возрасту и льготам — пригодится даже в жизни
Это не учебник. Это фундамент.
После этой серии if перестанет быть пугающим, а начнёт работать на вас.
💸 Поддержать канал и скачать серию можно здесь
📣 И да, поставь реакцию за старание
👉 Senior Data Analyst | #python #модуль_03 #серия_01
Когда «управление логикой» звучит не как философия, а как реальный навык
Это первая серия модуля 3 — и она про то, как писать условия, не превращаясь в программиста 2008 года.
Что внутри:
→ на пальцах объясняем, как работает
if, elif, else
→ 10 примеров с комментариями: от “число положительное?” до “если всё сложно, делай красиво
”→ практическое задание: определяем возрастную категорию
→ советы и фейлы: как не закопаться в условиях и не получить
else: print('что-то пошло не так')
→ реальный кейс: расчёт налога по типу дохода, возрасту и льготам — пригодится даже в жизни
Это не учебник. Это фундамент.
После этой серии if перестанет быть пугающим, а начнёт работать на вас.
💸 Поддержать канал и скачать серию можно здесь
📣 И да, поставь реакцию за старание
👉 Senior Data Analyst | #python #модуль_03 #серия_01
🔥6❤5
🧠 Как писать свои SQL‑функции в PostgreSQL — и зачем это нужно?
Собрали прод‑разбор:
– scalar, plpgsql и TVF функции с реальными кейсами;
– зачем нужны IMMUTABLE и STABLE;
– как вынести бизнес‑логику в UDF и перестать дублировать CASE‑ы;
– примеры для сегментации, нормализации, топ‑N.
Сделайте свои витрины легче, код — чище, и отчёты — стабильнее.
💸 Поддержать канал
👉 Senior Data Analyst | #sql
Собрали прод‑разбор:
– scalar, plpgsql и TVF функции с реальными кейсами;
– зачем нужны IMMUTABLE и STABLE;
– как вынести бизнес‑логику в UDF и перестать дублировать CASE‑ы;
– примеры для сегментации, нормализации, топ‑N.
Сделайте свои витрины легче, код — чище, и отчёты — стабильнее.
💸 Поддержать канал
👉 Senior Data Analyst | #sql
👍9
🧠 Зачем вообще SQL-функции, если можно просто написать SELECT?
На ранних этапах всё просто: CASE WHEN, пара JOIN-ов, и ты доволен.
Но с ростом проекта — и твоим опытом — появляется ощущение, что код начинает душить.
Когда проект растёт, вместе с ним растёт и боль:
• дублирующаяся логика
• громоздкие CASE WHEN
• правила, разбросанные по десяткам CTE
• метрика меняется — ты бегаешь по скриптам с огнетушителем
Вот тут и заходят на сцену SQL-функции (UDF).
Они позволяют вынести логику в одно место. Изолированно. Переиспользуемо. Как функции в коде, только внутри БД.
▪️ Какие бывают функции в PostgreSQL?
• Скалярные
Используются в метриках, флагах, категоризациях
• Табличные
Удобны для создания витрин и кастомных выборок с параметрами
• Агрегатные
Нужны, если стандартных агрегатов мало или не подходят
▪️Реальные кейсы
1️⃣ Категоризация пользователей
Было:
Стало:
→ читается, тестируется, правится в одном месте
2️⃣ Флаг аномалии
→ можно использовать в WHERE, CASE, JOIN, даже в dbt-тестах
3️⃣ Параметризуемая витрина
→ больше не пишешь ROW_NUMBER вручную в каждом скрипте
▪️IMMUTABLE, STABLE, VOLATILE — важнее, чем кажется
•
→ используется для расчётов
•
→ подходит для
•
→
Если не указать тип, PostgreSQL подставит VOLATILE, и оптимизации не будет. А это уже тормоза.
▪️Тестирование UDF
Функции можно (и нужно) тестировать:
• pgTAP — юнит-тесты прямо в PostgreSQL
• ручные тесты через begin...end
• автотесты через CI: пушнул код — сравнил результат
▪️Как устроено в проде
1. Версионирование
→ переключаешь alias, не ломаешь пайплайн
2. Интеграция с dbt и Airflow
→ в
→ в Airflow — вызываешь в
3. Документация
→
→ changelog логики — в доках проекта
▪️Типичные ошибки
• писать скалярную функцию, которая делает SELECT
→ это отдельный запрос на каждую строку → тормозит
• не указывать IMMUTABLE или STABLE
→ теряется кеш, растёт нагрузка
• изменять функции без версионирования
→ одно изменение — и всё падает
• писать гигантские UDF без профилирования
→ сложно читать, плохо оптимизируется
▪️Вывод
SQL-функции — про стабильность, переиспользуемость и контроль.
Они дают тебе одно: уверенность, что логика работает так, как ты задумал. И что её не нужно чинить каждую неделю.
💸 Поддержать канал
👉 Senior Data Analyst | #sql
На ранних этапах всё просто: CASE WHEN, пара JOIN-ов, и ты доволен.
Но с ростом проекта — и твоим опытом — появляется ощущение, что код начинает душить.
Когда проект растёт, вместе с ним растёт и боль:
• дублирующаяся логика
• громоздкие CASE WHEN
• правила, разбросанные по десяткам CTE
• метрика меняется — ты бегаешь по скриптам с огнетушителем
Вот тут и заходят на сцену SQL-функции (UDF).
Они позволяют вынести логику в одно место. Изолированно. Переиспользуемо. Как функции в коде, только внутри БД.
▪️ Какие бывают функции в PostgreSQL?
• Скалярные
normalize(score, avg, sd)
→ возвращают одно значениеИспользуются в метриках, флагах, категоризациях
• Табличные
top_n_per_category(n)
→ возвращают таблицуУдобны для создания витрин и кастомных выборок с параметрами
• Агрегатные
my_median(val)
→ агрегируют значенияНужны, если стандартных агрегатов мало или не подходят
▪️Реальные кейсы
1️⃣ Категоризация пользователей
Было:
CASE WHEN spend > 10000 AND visits > 5 THEN 'VIP' ...
Стало:
customer_segment(spend, visits)
→ читается, тестируется, правится в одном месте
2️⃣ Флаг аномалии
is_outlier(val, avg, stddev)
→ можно использовать в WHERE, CASE, JOIN, даже в dbt-тестах
3️⃣ Параметризуемая витрина
SELECT * FROM top_n_per_category(3)
→ больше не пишешь ROW_NUMBER вручную в каждом скрипте
▪️IMMUTABLE, STABLE, VOLATILE — важнее, чем кажется
•
IMMUTABLE
— всегда даёт одинаковый результат при одних и тех же аргументах→ используется для расчётов
(abs(x), normalize(...))
•
STABLE
— может читать таблицы, но не меняет данные→ подходит для
SELECT ... WHERE id = x
•
VOLATILE
— может вести себя непредсказуемо→
random(), now(), count(*)
Если не указать тип, PostgreSQL подставит VOLATILE, и оптимизации не будет. А это уже тормоза.
▪️Тестирование UDF
Функции можно (и нужно) тестировать:
• pgTAP — юнит-тесты прямо в PostgreSQL
• ручные тесты через begin...end
• автотесты через CI: пушнул код — сравнил результат
SELECT customer_segment(11000, 6) = 'VIP' AS test_1;
▪️Как устроено в проде
1. Версионирование
segment_v1
, segment_v2
, segment_active
→ переключаешь alias, не ломаешь пайплайн
2. Интеграция с dbt и Airflow
→ в
dbt
— используешь как обычную функцию→ в Airflow — вызываешь в
PostgresOperator
3. Документация
→
COMMENT ON FUNCTION
внутри тела→ changelog логики — в доках проекта
▪️Типичные ошибки
• писать скалярную функцию, которая делает SELECT
→ это отдельный запрос на каждую строку → тормозит
• не указывать IMMUTABLE или STABLE
→ теряется кеш, растёт нагрузка
• изменять функции без версионирования
→ одно изменение — и всё падает
• писать гигантские UDF без профилирования
→ сложно читать, плохо оптимизируется
▪️Вывод
SQL-функции — про стабильность, переиспользуемость и контроль.
Они дают тебе одно: уверенность, что логика работает так, как ты задумал. И что её не нужно чинить каждую неделю.
💸 Поддержать канал
👉 Senior Data Analyst | #sql
❤8👍1
🧠 SQL-функции — ты с ними на «вы» или на «мы»?
Anonymous Poll
12%
"Функция? Это где скобки и запятые?.." (ещё немного — и освою SELECT *)
44%
"CASE WHEN — мой стиль. Но функции пугают." (вдруг сломаю что-то в проде)
12%
"Писал пару UDF. Работает — не трогаю." (и да, я однажды указал IMMUTABLE, горжусь этим)
17%
"UDF, pgTAP, версионирование, комментарии — это всё я" (и если ты не пишешь тесты — я немного грущу)
20%
"Прочитал пост, ничего не понял, но интересно." (хочу просто нажать кнопку и чтоб всё работало)
❤2
🧠 Погнали разогревать мозги — задачи ждут!
💸 Поддержать канал
👉 Senior Data Analyst | #матстат #теорвер
Если и есть день для чётких решений — это сегодня. Среда, энергия есть, мозг включён!
💸 Поддержать канал
👉 Senior Data Analyst | #матстат #теорвер
🔥6
🔵 Задача №1: Среднее или медиана?
Математическая статистика
Доходы в выборке (в рублях):
40 000, 42 000, 43 000, 44 000, 2 000 000
Какую метрику лучше использовать — среднее или медиану? Почему?
Разбор:
Среднее = (40к + 42к + 43к + 44к + 2млн)/5 ≈ 442 000
Медиана = 43 000
✅ Ответ:медиану
Среднее сильно искажено выбросом (2 млн). В таких случаях для описания "типичного" дохода лучше использовать медиану.
Это основа устойчивости статистик — всегда проверяй выбросы перед расчетом среднего!
🔵 Задача №2: Доверие к результату
Математическая статистика
Вы провели A/B-тест:
• Группа A: 5000 юзеров, конверсия — 5%
• Группа B: 100 юзеров, конверсия — 6%
Можно ли сказать, что B лучше?
Разбор:
Повышение есть (5% → 6%), но выборка в B слишком мала, чтобы делать вывод.
✅ Ответ:Нет, нельзя
Для вывода нужна статистическая значимость. При малом размере выборки возможна случайная флуктуация.
Хорошая практика: сначала убедись, что выборка достаточна, потом — смотри на конверсии и p-value.
🔴 Задача №3 : Монетка и игральный кубик
Теория вероятностей
Сначала подбрасываем честную монету.
Если выпал орёл — бросаем кубик один раз.
Если решка — бросаем кубик дважды и берём сумму.
Какова вероятность, что в итоге получим число 6?
Разбор:
Делим на 2 сценария:
1. Орёл → 1 бросок → P(выпадет 6) = 1/6
2.Решка → 2 броска → сколько комбинаций даёт сумму 6?
Варианты:
(1,5), (2,4), (3,3), (4,2), (5,1) — 5 из 36
Общий ответ:
P = 0.5 × (1/6) + 0.5 × (5/36) = (3/36) + (5/72) = 0.2083… ≈ 20.8%
✅ Ответ:≈ 20.8%
Тут важна комбинация условной и полной вероятности, учитывая разные сценарии.
🔴 Задача №4 : День рождения в команде
Теория вероятностей
В команде из 23 человек — какова вероятность, что у хотя бы двух день рождения в один день?
(Принять 365 дней в году, игнорируем високосные)
Разбор:
Эта задача известна как парадокс дня рождения.
Вместо прямого счёта — удобнее посчитать обратное событие:
P(все разные) ≈ 0.493
365/365 × 364/365 × 363/365 × ... × 343/365 ≈ 0.4927
Шанс, что все 23 дня рождения разные → 49%
Но, нас-то интересует обратное событие —
что хотя бы у кого-то дни рождения совпадут:
→ P(хотя бы совпадение) = 1 – 0.493 = 0.507
✅ Ответ:≈ 50.7%
Парадокс: всего 23 человека, а шанс совпадения уже больше 50%!
Классический пример, где человеческая интуиция сильно ошибается.
Математическая статистика
Доходы в выборке (в рублях):
40 000, 42 000, 43 000, 44 000, 2 000 000
Какую метрику лучше использовать — среднее или медиану? Почему?
Разбор:
Медиана = 43 000
✅ Ответ:
Это основа устойчивости статистик — всегда проверяй выбросы перед расчетом среднего!
🔵 Задача №2: Доверие к результату
Математическая статистика
Вы провели A/B-тест:
• Группа A: 5000 юзеров, конверсия — 5%
• Группа B: 100 юзеров, конверсия — 6%
Можно ли сказать, что B лучше?
Разбор:
✅ Ответ:
Хорошая практика: сначала убедись, что выборка достаточна, потом — смотри на конверсии и p-value.
🔴 Задача №3 : Монетка и игральный кубик
Теория вероятностей
Сначала подбрасываем честную монету.
Если выпал орёл — бросаем кубик один раз.
Если решка — бросаем кубик дважды и берём сумму.
Какова вероятность, что в итоге получим число 6?
Разбор:
1. Орёл → 1 бросок → P(выпадет 6) = 1/6
2.Решка → 2 броска → сколько комбинаций даёт сумму 6?
Варианты:
(1,5), (2,4), (3,3), (4,2), (5,1) — 5 из 36
Общий ответ:
P = 0.5 × (1/6) + 0.5 × (5/36) = (3/36) + (5/72) = 0.2083… ≈ 20.8%
✅ Ответ:
🔴 Задача №4 : День рождения в команде
Теория вероятностей
В команде из 23 человек — какова вероятность, что у хотя бы двух день рождения в один день?
(Принять 365 дней в году, игнорируем високосные)
Разбор:
Вместо прямого счёта — удобнее посчитать обратное событие:
P(все разные) ≈ 0.493
365/365 × 364/365 × 363/365 × ... × 343/365 ≈ 0.4927
Шанс, что все 23 дня рождения разные → 49%
Но, нас-то интересует обратное событие —
что хотя бы у кого-то дни рождения совпадут:
→ P(хотя бы совпадение) = 1 – 0.493 = 0.507
✅ Ответ:
Классический пример, где человеческая интуиция сильно ошибается.
🔥7❤1
🧠 Сколько задач ты осилил без гугла и калькулятора?
По-честному, без геройства:
По-честному, без геройства:
Anonymous Poll
16%
Все добил — мозг кипит, но приятно 💪
47%
2–3 штуки — где-то вспомнил, где-то угадал 😅
16%
Одну кое-как вытянул. Теперь хотя бы знаю, что такое дисперсия
24%
Просто полистал... но орёл и решка звучит знакомо 🪙
🔥5
🧠 Почему аналитик дважды подумает, прежде чем писать IFNULL, ROUND, CAST, NOW()
и что потом с этим делать, когда всё сломалось
Потому что эти штуки:
— тихо маскируют ошибки (NULL → 0, и привет кривой отчёт)
— ломают агрегации (ROUND в строках → минус доверие к итогам)
— ведут к нестабильности (NOW() в проде ≠ NOW() в dev)
— создают магию, которую потом никто не может воспроизвести
Вместо встроенных хакающих функций —
нормальные SQL-функции с понятной логикой, версионированием, комментариями и тестами.
В посте:
• разбор, почему эти функции опасны
• читаемые примеры
• как писать надёжный SQL
💸 Поддержать канал
👉 Senior Data Analyst | #sql
и что потом с этим делать, когда всё сломалось
Потому что эти штуки:
— тихо маскируют ошибки (NULL → 0, и привет кривой отчёт)
— ломают агрегации (ROUND в строках → минус доверие к итогам)
— ведут к нестабильности (NOW() в проде ≠ NOW() в dev)
— создают магию, которую потом никто не может воспроизвести
"Лишь бы работало" — не подход.
Вместо встроенных хакающих функций —
нормальные SQL-функции с понятной логикой, версионированием, комментариями и тестами.
В посте:
• разбор, почему эти функции опасны
• читаемые примеры
• как писать надёжный SQL
💸 Поддержать канал
👉 Senior Data Analyst | #sql
👍7❤1
▪️Что не так?
Базовые SQL-функции кажутся удобными.
Но если применять их бездумно — это путь к тихим багам, кривым отчётам и вечному “а почему здесь 0?”
▪️Где сыпется чаще всего:
COALESCE / IFNULL
Выглядит мило:
Но скрывает NULL и мешает понять, откуда дыра.
В результате ты "лечишь" витрину, которая уже умерла.
Правильно:
→ Комментируй замену:
→ Лучше —
Кейс: retention по оплатам. Пользователь не платил → NULL → подставили 0 → метрика выросла. Радоваться рано.
▪️ ROUND(..., 2)
Если ты округляешь до суммы — всё норм.
Если до — всё грустно.
Раннее округление:
→ копится погрешность
→ сумма строк != total
→ отчёт бьётся по швам
Правильно:
→ округляем после агрегации
→ лучше в обёртке типа
▪️NOW() / CURRENT_TIMESTAMP
Самая коварная “удобная” функция.
Каждый вызов может вернуть разное время.
В prod — ок, в тесте — ничего не сходится.
Airflow, dbt — сбиваются от timezone или минуты запуска.
Правильно:
→ один clock_timestamp() в CTE
→ или передавай дату явно
→ всегда указывай
▪️CAST()
А ты не в курсе, потому что SQL промолчал.
Правильно:
→
→ логировать NULL
→ комментировать формат явно
Кейс: отчёт по регистрациям. Столбец с '0000-00-00' → стал NULL → “а почему у нас 300 юзеров без даты?”
▪️ Как бы думал я
• Junior: “лишь бы работало”
• Senior: “чтобы было читаемо, проверяемо и поддерживаемо”
Вместо встроенных функций — оборачивай бизнес-логику в UDF:
→ видно, что происходит
→ можно покрыть тестами
→ можно писать changelog
▪️ Ну и куда, без тестов
• pgTAP или ручные проверки
• edge-cases: NULL, пустые строки, нули, текст
• COMMENT ON FUNCTION, changelog, CI с EXPLAIN ANALYZE
▪️ Кейс: баг, который "починили", а стало хуже
Ситуация: отчёт по выручке. Где-то в исходных данных
Аналитик пишет:
Отчёт выходит нормальным. Все рады. Только потом выясняется:
эти пользователи вообще не должны были попасть в выборку.
0 вместо NULL скрыл баг в логике JOIN, и теперь все графики — фальшивка.
Как нужно было сделать:
1. Заменил бы NULL — и задал вопрос: "почему здесь нет данных?"
2. Временная замена? Только с явным AS
3. Логика обработки — в отдельную UDF с бизнес-смыслом.
4. Плюс флажок
Не всякий NULL — враг. Иногда он — единственный сигнал, что что-то пошло не так.
💥 Как тебе ?
🔥 — узнал(а) что-то новое
🤝 — темы хорошо знакомы
💸 Поддержать канал
👉 Senior Data Analyst | #sql
Базовые SQL-функции кажутся удобными.
Но если применять их бездумно — это путь к тихим багам, кривым отчётам и вечному “а почему здесь 0?”
▪️Где сыпется чаще всего:
COALESCE / IFNULL
Выглядит мило:
COALESCE(value, 0)
Но скрывает NULL и мешает понять, откуда дыра.
В результате ты "лечишь" витрину, которая уже умерла.
Правильно:
→ Комментируй замену:
AS logic_zero_substitute
→ Лучше —
is_data_missing
как отдельная колонкаКейс: retention по оплатам. Пользователь не платил → NULL → подставили 0 → метрика выросла. Радоваться рано.
▪️ ROUND(..., 2)
Если ты округляешь до суммы — всё норм.
Если до — всё грустно.
Раннее округление:
→ копится погрешность
→ сумма строк != total
→ отчёт бьётся по швам
Правильно:
→ округляем после агрегации
→ лучше в обёртке типа
adjust_for_report(val)
▪️NOW() / CURRENT_TIMESTAMP
Самая коварная “удобная” функция.
Каждый вызов может вернуть разное время.
В prod — ок, в тесте — ничего не сходится.
Airflow, dbt — сбиваются от timezone или минуты запуска.
Правильно:
→ один clock_timestamp() в CTE
→ или передавай дату явно
→ всегда указывай
UTC
▪️CAST()
CAST('' AS INT)
— NULLCAST('2024-12-40' AS DATE)
— NULLА ты не в курсе, потому что SQL промолчал.
Правильно:
→
TRY_CAST
, если есть→ логировать NULL
→ комментировать формат явно
Кейс: отчёт по регистрациям. Столбец с '0000-00-00' → стал NULL → “а почему у нас 300 юзеров без даты?”
▪️ Как бы думал я
• Junior: “лишь бы работало”
• Senior: “чтобы было читаемо, проверяемо и поддерживаемо”
Вместо встроенных функций — оборачивай бизнес-логику в UDF:
adjusted_spend(spend, rate)
→ видно, что происходит
→ можно покрыть тестами
→ можно писать changelog
▪️ Ну и куда, без тестов
• pgTAP или ручные проверки
• edge-cases: NULL, пустые строки, нули, текст
• COMMENT ON FUNCTION, changelog, CI с EXPLAIN ANALYZE
▪️ Кейс: баг, который "починили", а стало хуже
Ситуация: отчёт по выручке. Где-то в исходных данных
revenue = NULL
, потому что JOIN
не сработал.Аналитик пишет:
SELECT COALESCE(revenue, 0) AS revenue_cleaned
Отчёт выходит нормальным. Все рады. Только потом выясняется:
эти пользователи вообще не должны были попасть в выборку.
0 вместо NULL скрыл баг в логике JOIN, и теперь все графики — фальшивка.
Как нужно было сделать:
1. Заменил бы NULL — и задал вопрос: "почему здесь нет данных?"
2. Временная замена? Только с явным AS
zero_if_missing
и комментарием.3. Логика обработки — в отдельную UDF с бизнес-смыслом.
4. Плюс флажок
is_data_missing
, чтобы не потерять контекст.Не всякий NULL — враг. Иногда он — единственный сигнал, что что-то пошло не так.
💥 Как тебе ?
🔥 — узнал(а) что-то новое
🤝 — темы хорошо знакомы
💸 Поддержать канал
👉 Senior Data Analyst | #sql
🔥7👍4❤2
🧠 Как ускорять SQL-запросы?
Если ты всё ещё веришь в “индекс спасёт всегда” — у меня для тебя EXPLAIN ANALYZE.
В посте:
– читаем план запроса, не глядя в потолок
– разбираем cost, actual rows, loops
– находим, где JOIN душит, а GROUP BY тормозит
– учимся ускорять без пересоздания БД
EXPLAIN — это рентген твоего SQL.
Хочешь писать запросы, которые не тормозят? Погнали 👇
💸 Поддержать канал
👉 Senior Data Analyst | #sql
Если ты всё ещё веришь в “индекс спасёт всегда” — у меня для тебя EXPLAIN ANALYZE.
В посте:
– читаем план запроса, не глядя в потолок
– разбираем cost, actual rows, loops
– находим, где JOIN душит, а GROUP BY тормозит
– учимся ускорять без пересоздания БД
EXPLAIN — это рентген твоего SQL.
Хочешь писать запросы, которые не тормозят? Погнали 👇
💸 Поддержать канал
👉 Senior Data Analyst | #sql
🔥3👏3