Аналитика FM
17 постов
Если ты когда-нибудь писал длинный SQL-запрос и в какой-то момент ловил себя на мысли:
"Я уже сам не понимаю, что здесь происходит" - поздравляю, ты подошёл к моменту, где появляются временные таблицы.
В канале Аналитика FM я часто разбираю такие ситуации - когда задача вроде решаема, но без нормальной структуры превращается в кашу.
Это обычная таблица…
только с одним отличием:
👉 она живёт временно и потом исчезает
Ты создаёшь её:
чтобы сохранить промежуточный результат
поработать с ним
и не засорять основную базу
Тебе нужно:
взять заказы
отфильтровать только оплаченные
посчитать выручку
добавить сегментацию пользователей
ещё пару условий сверху
Можно написать один огромный запрос.
А можно сделать по-другому:
Сначала собрать "чистые заказы"
Потом на их основе считать метрики
Потом добавлять бизнес-логику
И вот тут временные таблицы начинают играть.
Как это выглядит
CREATE TEMP TABLE temp_orders AS
SELECT *
FROM orders
WHERE status = 'paid';
Создаем промежуточный слой данных.
А потом работаем уже с ним.
SELECT user_id, SUM(amount)
FROM temp_orders
GROUP BY user_id;
Вместо одного "монстра":
ты разбиваешь задачу на шаги
каждый шаг понятен
легче дебажить
Если один и тот же кусок данных нужен несколько раз:
не нужно каждый раз пересчитывать
можно сохранить и использовать
Иногда:
тяжёлый JOIN
сложная фильтрация
👉 выгодно посчитать один раз и сохранить результат
Если ты создашь обычную таблицу:
она останется
её надо потом удалять
она может мешать другим
Временная таблица:
живёт в рамках сессии
автоматически исчезает
сложные аналитические расчёты
многоступенчатые преобразования данных
работа с "грязными" данными
отладка логики
Временные таблицы - это не единственный инструмент.
Есть ещё:
CTE (WITH)
подзапросы
Но:
👉 CTE - это "логика в одном запросе"
👉 временные таблицы - это "разбивка на реальные шаги"
Иногда CTE читается тяжело.
А временные таблицы дают ощущение "пайплайна".
создают временные таблицы без необходимости
забывают, что они завязаны на сессию
используют их там, где проще CTE
То есть это инструмент - не серебряная пуля.
Самая простая мысль
Временная таблица - это способ остановиться посередине запроса и зафиксировать результат
И иногда именно это спасает:
читаемость
производительность
и твои нервы
В канале Аналитика FM (клик :-) )я рассказываю про продуктовые метрики в разных бизнесах. В чем особенности и нюансы. Серия постов про средний чек уже готова.
Подписывайся, если интересно интересно разбираться в особенностях работы аналитика.
Представь обычную ситуацию:
Есть клиент, сегодня он живет в Москве
| user_id | city |
| ----------- | ------------- |
| 1 | Москва |
Проходит время, он переезжает в Санкт-Петербург
Ты обновляешь данные
| user_id | city |
| ----------- | ---------------------------- |
| 1 | Санкт-Петербург|
И вроде всё ок.
Но потом приходит задача:
👉 А посчитай выручку по городам за прошлый год
И тут начинается самое интересное.
А в моем канале Аналитика FM выпуски про расчет Cohort Retention в разных бизнесах.
Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Подписывайся, если интересно как устроен мир аналитика!
Если ты просто возьмешь текущие данные, то все заказы пользователя "уедут " в Санкт-Петербург. Даже те, которые он делал, когда жил в Москве.
И аналитика начнёт врать.
Не потому что ты ошибся.
А потому что данные потеряли свою историю.
SCD (Slowly Changing Dimension) - это способ хранить изменения так,
чтобы ты мог ответить не только на вопрос:
👉 Как сейчас?
но и на более важный:
👉 Как было в момент события?
Как будет выглядеть: вместо одной строки в таблице будет:
| user_id | city | start_date | end_date |
| ------------ | --------------------------- | ----------------- | -------------------- |
| 1 | Москва | 2024-01-01 | 2025-01-01 |
| 1 | Санкт-Петербург| 2025-01-01 | NULL |
Теперь у нас есть не просто данные,
а контекст во времени.
Потому что почти всё в бизнесе меняется:
клиенты переходят между сегментами
продукты меняют категории
условия договоров обновляются
статусы живут своей жизнью
И если ты смотришь только на "сейчас" - ты теряешь половину смысла.
SCD - это не про таблицы.
Это про мышление.
Когда ты начинаешь задавать вопросы так:
А на момент события это было актуально?
А не поменялось ли это потом?
- ты переходишь на другой уровень понимания данных.
Берут текущие данные
и применяют их к прошлым событиям.
И получается:
красивые отчёты
аккуратные цифры
полностью неверные выводы
Данные без времени - это половина правды
SCD - это как раз про то, чтобы эту вторую половину не потерять.
И если тебе интересно разбираться в таких вещах глубже -
не просто "как написать SELECT", а как думать про данные,
в Аналитика FM я как раз про это и пишу.
Или превращение длинной таблицы в широкую
В канале Аналитика FM я часто про это пишу - потому что аналитика заканчивается не на запросе, а на том, как ты показал результат.
Подписывайся!
Представь, у тебя есть данные:
| user_id | metric | value |
| ----------- | ------------- | -------- |
| 1 | revenue | 100 |
| 1 | orders | 2 |
Это длинная таблица.
Она удобна для хранения:
гибкая
легко добавлять новые метрики
хорошо ложится в модели данных
Но попробуй быстро понять:
кто сколько потратил
у кого сколько заказов
и сравнить это между собой
Неудобно.
А теперь та же информация:
| user_id | revenue | orders |
| ------------ | ------------- | ---------- |
| 1 | 100 | 2 |
Это широкая таблица.
И вот тут уже:
метрики рядом
сравнение - в одну секунду
можно считать новые показатели
Это значит:
взять значения из строк и разложить их по колонкам
То есть:
metric → становится названиями колонок
value → становится значениями в этих колонках
Ты буквально "разворачиваешь" данные.
На самом деле, это и есть pivot.
Слово pivot - это "поворот".
Ты поворачиваешь таблицу так, чтобы:
строки стали колонками
данные стали наглядными
Если ты работал в Excel - ты это уже делал:
сводная таблица = pivot table.
В SQL это можно реализовать так:
SELECT
user_id,
SUM(CASE WHEN metric = 'revenue' THEN value END) AS revenue,
SUM(CASE WHEN metric = 'orders' THEN value END) AS orders
FROM table
GROUP BY user_id;
Потому что аналитика - это не про "достать данные".
Это про сделать их понятными.
Широкая таблица нужна, когда ты:
строишь отчёт
показываешь результат бизнесу
считаешь метрики между собой
Длинная таблица - когда:
хранишь данные
работаешь с событиями
строишь модели
Самая частая ошибка - пытаться всё делать в широком формате.
Это ломает гибкость:
добавилась новая метрика → переписывай запрос
данные перестают масштабироваться
Правильный подход:
храним - в длинном виде
показываем - в широком
Длинная таблица - это про хранение
Широкая таблица - это про понимание
И pivot - это просто инструмент, который помогает перейти от одного к другому.
И если ты хочешь не просто писать SQL, а реально чувствовать данные и понимать, как их правильно показывать,
в Аналитика FM я как раз разбираю такие вещи - простым языком, но с реальным смыслом.
Если ты только начинаешь разбираться в данных, то очень быстро сталкиваешься с кучей аббревиатур.
DDL, DML, ещё что-то… И кажется, что это какие-то сложные термины из учебника.
Но на самом деле всё гораздо проще.
И в канале Аналитика FM я как раз стараюсь разбирать такие вещи без заумных формулировок - через логику и реальные сценарии.
есть стены
есть комнаты
есть мебель
И есть вещи, которые ты туда кладёшь.
Так вот:
👉 DDL - это про квартиру
👉 DML - это про вещи внутри неё
DDL (Data Definition Language) - это команды, которые создают и изменяют структуру базы.
То есть всё, что связано с "построить" или "переделать".
CREATE TABLE users (...);
ALTER TABLE users ADD COLUMN age INT;
DROP TABLE users;
CREATE - ты создал новую "комнату"
ALTER - передвинул стену или добавил полку
DROP - снёс всё к чертям
📌 Важно:
DDL не трогает сами данные.
Он создаёт условия, где эти данные будут жить.
DML (Data Manipulation Language) - это уже про работу с данными.
SELECT * FROM users;
INSERT INTO users VALUES (...);
UPDATE users SET age = 30;
DELETE FROM users WHERE id = 1;
Это то, что делает аналитик каждый день:
посмотрел данные (SELECT)
добавил (INSERT)
изменил (UPDATE)
удалил (DELETE)
📌 Здесь ты уже работаешь не с "комнатой", а с тем, что внутри неё.
Не в терминах, а в сути:
DDL отвечает на вопрос: Как устроены данные?
DML отвечает на вопрос: Что происходит с данными?
Тебе нужно посчитать метрику.
Но:
нет нужной таблицы
не хватает колонок
данные лежат неудобно
👉 Тогда сначала приходит DDL:
создают таблицу, добавляют поля, настраивают структуру.
И только потом приходит DML:
ты пишешь SELECT, считаешь, анализируешь.
DDL и DML - это не просто разные команды.
Это разные уровни ответственности.
DDL чаще делают разработчики, инженеры, архитекторы
DML - это зона аналитиков
Но хороший аналитик всё равно должен понимать DDL.
Иначе он не понимает, почему данные лежат именно так.
DDL обычно:
применяется сразу
сложнее откатывается
DML:
можно обернуть в транзакцию
можно отменить
Это важно, когда ты начинаешь работать не только с SELECT, но и с изменением данных.
DDL - это "построить систему"
DML - это "жить внутри неё и работать с данными"
Если ты хочешь начать действительно понимать данные, а не просто писать запросы -
такие базовые вещи дают фундамент.В канале Аналитика FM я как раз разбираю такие темы:
без усложнений, но с пониманием того, как это работает в реальной работе аналитика.Разбор метрик Retention и Revenue в разных сферах бизнеса уже в канале.
Подписывайся!
Мы обычно пишем запросы: SELECT, INSERT, UPDATE…
Это отдельные команды, и каждая выполняется сама по себе. Но иногда нам хочется написать целую мини-программу, которая делает несколько действий сразу: например, берёт данные из одной таблицы, считает что-то, обновляет другую таблицу и выводит результат.
И при этом нам не нужно, чтобы эта программа сохранялась в базе как функция или процедура - мы просто хотим один раз выполнить код.
Вот для этого и нужен анонимный блок.
А в моем канале Аналитика FM выпуски про расчет Cohort Retention в разных бизнесах.
Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Подписывайся, если интересно как устроен мир аналитика!
Анонимный блок - это кусок кода, который:
Объединяет несколько SQL-команд в одну "программу".
Может содержать переменные, условия (IF), циклы (LOOP) и логику, как в обычной программе.
Не сохраняется в базе - после выполнения он исчезает. Его никто не будет видеть в списке функций или процедур.
То есть это как написать одноразовый скрипт: ты его запускаешь, видишь результат - и больше он никуда не сохраняется.
Пример в Oracle PL/SQL
BEGIN
-- объявляем переменную
DECLARE
v_count NUMBER;
BEGIN
-- считаем количество записей в таблице users
SELECT COUNT(*) INTO v_count FROM users;
-- выводим результат
DBMS_OUTPUT.PUT_LINE('Всего пользователей: ' || v_count);
END;
END;
/
Что здесь происходит:
BEGIN ... END; - тело блока, где выполняется логика.
DECLARE - можно объявлять переменные.
SQL-команда SELECT ... INTO считает количество пользователей и кладёт в переменную.
DBMS_OUTPUT.PUT_LINE выводит текст на экран.
/ - говорит Oracle, что блок закончился и его нужно выполнить.
После выполнения блока: переменные исчезают, код никуда не сохраняется, всё "одноразовое".
Пример в PostgreSQL
В PostgreSQL нет точно такого же синтаксиса, но есть DO-блок:
DO $$
DECLARE
v_count INT;
BEGIN
SELECT COUNT(*) INTO v_count FROM users;
RAISE NOTICE 'Всего пользователей: %', v_count;
END
$$;
DO $$ ... $$; - обёртка для анонимного блока. Мы говорим базе, что сейчас идет блок кода, который нужно выполнить целиком как отдельную программу.
Объявляем переменную v_count. Она нам нужна, чтобы сохранить результат вычислений и использовать его дальше внутри блока.
Все, что внутри BEGIN ... END, выполняется пошагово как мини-программа. Считаем количество строк в таблице users и записываем это значение в объявленную переменную
RAISE NOTICE выводит сообщение. % заменяется на значение переменной v_count.
Разовая операция. Хочешь разово обновить данные или проверить что-то - не нужно создавать отдельную функцию.
Тестирование логики. Пробуешь алгоритм, проверяешь, как работает SQL вместе с переменными и условиями.
Быстрое прототипирование. Хочешь понять, как соединить несколько шагов в одну последовательность действий.
Анонимный блок - это как одноразовый скрипт в SQL, который можно писать прямо в базе. Он может быть сложным, с переменными и логикой, но после выполнения исчезает.
Для аналитика это полезно, если нужно быстро посчитать что-то, проверить гипотезу или сделать массовую корректировку данных, не создавая постоянную функцию или процедуру.
В канале Аналитика FM разбираем реальные продуктовые метрики и их реализацию на SQL. Погружаемся в мира аналитики и аналитического мышления.
Если у тебя тоже есть интерес к аналитике,
Подписывайся!
Очень часто в аналитике смотрят на среднее:
средний чек
среднее время
средний доход
Но среднее - коварная штука.
Оно сглаживает реальность.
Если у 9 человек чек 100 ₽, а у одного - 10 000 ₽,
среднее будет 1 090 ₽.
И это вообще не похоже на реальность большинства.
Вот здесь и появляется перцентиль.
Подписывайся, если интересно как устроен мир аналитика!
В моем канале Аналитика FM выпуски про расчет Retention в разных бизнесах.Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Перцентиль это значение, ниже которого находится определённый процент данных.
Например:
50-й перцентиль (P50) - это медиана
90-й перцентиль (P90) - значение, ниже которого 90% наблюдений
95-й перцентиль (P95) - ещё более "правый хвост"
Если сказать по-человечески:
P90 - это "как живёт большинство, кроме самых крайних случаев".
Идея очень простая:
Берём все значения
Сортируем их по возрастанию
Берём нужную позицию
Например, у нас 100 значений:
P50 → 50-е значение
P90 → 90-е значение
В реальности всё чуть сложнее (интерполяции, разные методы расчёта),
но логика именно такая.
Во многих СУБД есть встроенные функции.
Например:
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY amount)
Это P90 по полю amount.
Или:
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY duration)
Это медиана.
Среднее время ответа может быть нормальным,
но пользователи всё равно недовольны.
Почему?
Потому что:
90% запросов - быстрые
10% - очень медленные
И именно эти 10% формируют опыт.
Поэтому смотрят:
P90
P95
P99
Средний чек может быть завышен из-за крупных покупок.
Перцентили показывают:
как платит "обычный" клиент
где начинается премиум-сегмент
Средняя зарплата - почти всегда вводит в заблуждение.
Перцентили дают реальную картину:
P50 - "типичный доход"
P90 - "верх рынка"
В продуктовой аналитике:
сколько времени пользователь тратит на действие
сколько длится сессия
Среднее не показывает хвосты.
Перцентили - показывают.
Один аномально большой показатель не сломает картину.
Среднее - это одна точка.
Перцентили - это уже форма данных.
Пользователь - это не "среднее значение".
Он где-то внутри распределения.
Не только в аналитике:
Инженерия и DevOps - latency, SLA
Финансы - оценка рисков
Медицина - рост, вес, показатели анализов
Образование - результаты тестов
Логистика - время доставки
Везде, где важно понимать не "в среднем",
а "как распределены значения".
Важно помнить:
при маленьких выборках они нестабильны
разные системы могут считать их по-разному
P99 может сильно "скакать"
И ещё:
перцентили не заменяют среднее - они его дополняют
Перцентиль - это способ перестать думать "в среднем"
и начать видеть, как данные распределены на самом деле.
Потому что в аналитике
самые важные вещи часто происходят
не в центре,
а на краях.
В канале Аналитика FM разбираем реальные продуктовые метрики и их реализацию на SQL. Погружаемся в мира аналитики и аналитического мышления.
Если у тебя тоже есть интерес к аналитике,
Подписывайся!
Или зачем вообще нужен код-стайл в SQL?
Очень часто можно услышать:
Какая разница, как написан SQL код? Главное, чтобы запрос работал.
И формально это правда.
Если запрос возвращает правильные данные - задача вроде бы решена.
Об этом порассуждаем чуть ниже, а пока....
Подписывайся, если интересно как устроен мир аналитика!
В моем канале Аналитика FM выпуски про расчет Retention в разных бизнесах.Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Особенность того, что необходимо "использовать" код-стайл при написании SQL запросов заключается в том, что SQL почти никогда не пишется один раз.
Его:
читают коллеги
правят через полгода
копируют в другие отчёты
используют как основу для новых запросов
И вот в этот момент становится понятно, зачем существует код-стайл.
Код-стайл - это договорённость о том, как писать код, чтобы его было легко читать, понимать и поддерживать.
Это не про красоту ради красоты.
Это про понятность.
В код-стайл обычно входят правила:
форматирования запроса
именования таблиц и алиасов
расположения JOIN
оформления условий
структуры сложных запросов
По сути это язык, на котором разработчики и аналитики читают код друг друга.
SQL отличается от многих языков тем, что он декларативный.
Ты описываешь не процесс, а результат.
И если структура запроса хаотичная, читать его становится очень тяжело.
Посмотрите на такой запрос:
SELECT a.id,b.name,sum(o.amount)
FROM users a JOIN orders o ON a.id=o.user_id
JOIN products b ON o.product_id=b.id
WHERE o.status='paid' AND o.created_at>'2025-01-01'
GROUP BY a.id,b.name;
Он работает.
Но мозг тратит энергию просто на то, чтобы разобрать структуру.
Теперь тот же запрос, но оформленный:
SELECT
u.id,
SUM(o.amount) AS revenue
FROM users u
JOIN orders o
ON u.id = o.user_id
JOIN products p
ON o.product_id = p.id
WHERE o.status = 'paid'
AND o.created_at > '2025-01-01'
GROUP BY
u.id,
Логика читается почти как текст.
Чаще всего пишут в верхнем:
SELECT
FROM
WHERE
GROUP BY
Это помогает быстро видеть структуру запроса.
Структура запроса должна читаться сверху вниз:
SELECT
FROM
JOIN
WHERE
GROUP BY
HAVING
ORDER BY
Это базовая навигация по SQL.
Плохой вариант:
FROM users u, orders o
WHERE u.id = o.user_id
Хороший вариант:
FROM users u
JOIN orders o
ON u.id = o.user_id
Так видно:
какие таблицы участвуют
по каким ключам они связаны
4️⃣ Алиасы должны быть понятными
Плохой стиль:
SELECT a,b,c
FROM table1 t1
JOIN table2 t2
Хороший стиль:
users u
orders o
payments p
Код читается быстрее.
Вместо:
WHERE status='paid' AND created_at>'2025-01-01' AND country='DE'
Лучше:
WHERE status = 'paid'
AND created_at > '2025-01-01'
AND country = 'DE'
Так легче искать ошибки.
Плохой вариант:
SUM(amount)
Лучше:
SUM(amount) AS total_revenue
Через месяц вы не будете вспоминать, что именно считалось.
SQL-код почти всегда живет дольше, чем его автор помнит контекст.
Запрос, написанный сегодня:
могут открыть через год
могут использовать в другой задаче
могут передать другому аналитику
И если код написан хаотично, человек сначала будет разбираться в структуре, а уже потом в логике.
Уважение:
к коллегам
к будущему себе
к системе, в которой работает код
Потому что чаще всего через несколько месяцев вы открываете свой старый SQL…
и думаете:
Кто это вообще написал?
И очень приятно, когда ответ:
Я. И я понимаю, что здесь происходит.
В моем канале Аналитика FM все про мышление аналитика, про инструменты аналитика.
Мы рассматриваем SQL и Python в применении к данным.Этот канал я веду с нуля подписчиков. Если тебе тоже интересно погрузиться в мир аналитики, подписывайся!
Я недавно вышла в найм.
И попала в реальность, где компании активно импортозамещаются, переписывают монолиты, режут их на микросервисы…
Но историческая база при этом — на Oracle Database.
И если ты много лет работал с PostgreSQL, переключение ощущается не как «ну ладно, другая СУБД»,
а как смена диалекта с тем же словарём, но другой грамматикой.
Важно: это взгляд аналитика.
Не администратора.
Не архитектора.
А человека, который каждый день пишет SELECT.
1️⃣ Работа с NULL
COALESCE(value, 0)
Работает как и в большинстве СУБД.
NVL(value, 0)
Да, COALESCE тоже работает.
Но в легаси-коде ты почти везде увидишь NVL.
Для аналитика это значит:
читаешь чужой код - будь готов к другому синтаксису.
2️⃣ Ограничение строк (LIMIT)
SELECT *
FROM table
LIMIT 10;
В старых версиях:
SELECT *
FROM table
WHERE ROWNUM <= 10;
В новых версиях:
FETCH FIRST 10 ROWS ONLY
3️⃣ Работа с датами
Вот здесь начинаются настоящие нюансы.
Очень удобные конструкции:
CURRENT_DATE
NOW()
DATE_TRUNC('month', date_column)
AGE()
Интервалы читаются логично:
date_column + INTERVAL '1 month'
SYSDATE
TRUNC(date_column, 'MM')
ADD_MONTHS(date_column, 1)
4️⃣ Работа со строками
PostgreSQL:
STRING_AGG(column, ',')
Oracle:
LISTAGG(column, ',') WITHIN GROUP (ORDER BY ...)
Синтаксис разный, логика похожая.
А в моем канале Аналитика FM выпуски про расчет Retention в разных бизнесах.
Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Подписывайся, если интересно как устроен мир аналитика!
