← К портфолио SQL Analytics Case Study preview
Стек
SQLDuckDBPythonpandas / NumPypytest
Эффект
  • 10 self-contained SQL cases (funnel → attribution)
  • DuckDB — no server, no credentials, one command
  • Regression tests with deterministic invariants per case
  • Synthetic deterministic data (seed=42, ~183k events)

SQL Analytics Case Study

Business Context

Take-home–формат: 10 end-to-end SQL-кейсов на синтетическом продуктовом датасете. Каждый кейс — один самодостаточный .sql файл с вопросом и подходом в leading-комментарии. Без сервера, без кредов — одна команда строит данные и базу DuckDB.

Data & Method

Модель данных (синтетическая, seed=42, детерминированная):

СущностьОбъёмПоля
Users20,000 signups (Jan–Jun 2024)channel, country, device, ab_variant
Events~183k funnel-событийapp_open → view_item → add_to_cart → checkout → purchase, ~80k sessions
Orders~800 покупокamount, product category
Subscriptions~240 конверсийmonthly / annual plans

Схема: data/schema.sql. Генератор: data/generate_data.py. Engagement геометрически убывает от signup; retention взвешен каналом привлечения — когорты и каналы дают видимые нетривиальные различия.

10 кейсов:

#КейсТехника
01Funnel conversioncumulative counts, LAG / FIRST_VALUE
02N-day retention by cohortDATE_TRUNC('month', signup_date)
03Rolling 30-day retentionEXISTS subqueries per window
04DAU / MAU / stickinesstrailing-28d range join
05LTV by cohortleft join + COALESCE для zero-revenue
06Top-N categories per countryROW_NUMBER() OVER (PARTITION BY ...)
07Cumulative revenueSUM() ... UNBOUNDED PRECEDING
08Longest active-day streakgaps-and-islands (row_number → island key)
09A/B conversion by variantleft join, LAG для lift
10Revenue attributionfirst-touch vs lifetime, correlated subquery

Quick start

uv run --with duckdb --with pandas --with numpy python data/generate_data.py   # data/analytics.duckdb
uv run --with duckdb --with pandas python run.py            # список кейсов
uv run --with duckdb --with pandas python run.py 1          # запустить кейс 1
uv run --with duckdb --with pandas python run.py 4 --limit 20
uv run --with duckdb --with pandas --with numpy --with pytest pytest -q   # regression-тесты

Runner печатает вопрос кейса, выполняет SQL против data/analytics.duckdb, рендерит результат таблицей.

Insight

Каждый кейс покрывает конкретный оконно-функциональный паттерн, который встречается в реальных продуктовых задачах: cumulative counts, gaps-and-islands, partitioned Top-N, range-join для stickiness. Разделение вопроса и SQL в одном файле + regression-инварианты делают кейсы самопроверяемыми — запуск pytest подтверждает, что SQL продолжает давать ожидаемые метрики после любого изменения генератора.

Impact

  • 10 самодостаточных SQL-кейсов — от funnel до revenue attribution, каждый со своим оконным паттерном.
  • DuckDB без инфраструктуры — одна команда строит данные и базу; нет сервера, нет кредов.
  • Regression-тесты на кейс — детерминированные инварианты защищают от регрессий при изменении генератора.
  • Воспроизводимые данные (seed=42) — повторный запуск даёт идентичный результат.

Documentation

Разбор кейса

Проблема

Аналитику нужно показать владение SQL на продуктовых задачах, но продакшен-данных нет, а учебные задачи не демонстрируют системное мышление. Как доказать, что SQL — рабочий инструмент, а не набор заученных синтаксисов?

Подход

10 end-to-end кейсов на синтетическом датасете (seed=42, ~183k событий, 20k signups): каждый кейс — один самодостаточный .sql файл с вопросом и подходом в leading-комментарии. DuckDB — одна команда строит данные и базу, без сервера и кредов. Regression-тесты с детерминированными инвариантами защищают SQL от регрессий при изменении генератора.

Результат

10 кейсов от funnel до revenue attribution, каждый покрывает конкретный оконный паттерн (gaps-and-islands, partitioned Top-N, range-join для stickiness). Кейсы самопроверяемы: pytest подтверждает, что SQL продолжает давать ожидаемые метрики после любого изменения данных.

10 SQL-кейсов
~183k Событий в датасете
20k Signups
1 Команда для запуска