Все материалы
Бизнесгайдстарт

Как сделать дашборд: от вопроса бизнеса до публикации

Пошагово собираем дашборд на проверенных данных: решение и читатель, SQL для KPI, динамика, разрез, проверка чисел, доступы и дата обновления.

КейсПрактика27 сентября 2026 г.18 мин

Коммерческий директор просит к пятнице дашборд продаж. Аналитик может сразу открыть BI и расставить графики, но через неделю обнаружится спор о том, что считать продажей и почему сумма в отчёте не совпала с оплатами. Начните с решения, которое директор примет по странице. Ниже мы пройдём весь путь на учебных бронированиях авиабилетов: запросы выполнены, числа можно повторить, а ограничения данных показаны рядом с графиками.

Коротко: как сделать дашборд

Сформулируйте решение и того, кто будет открывать страницу. Зафиксируйте период, единицу учёта, определения показателей и источник. Сверьте SQL-расчёт с контрольной таблицей. Разложите экран сверху вниз: итоговые числа, динамика, объясняющий разрез, детали. Добавьте не более тех фильтров, которые меняют решение. Укажите время последнего успешного обновления, права доступа и владельца. Покажите страницу заказчику на реальном вопросе, затем возвращайтесь к ней после месяца использования.

Это не инструкция по кнопкам конкретного инструмента: они меняются. Практический результат — спецификация страницы, запросы и таблицы приёмки, которые можно перенести в Excel или BI. Если требуется только одноразовый ответ «почему изменились продажи в августе», нужен разовый анализ, а не постоянно поддерживаемый дашборд.

Начните с решения, а не с перечня KPI

Для учебного кейса вопрос руководителя звучит так: «Сумма новых бронирований за прошлую полную неделю выросла или уменьшилась по сравнению с предыдущей, и в каких типах брони это заметно?» Возможное действие — проверить изменение тарифа или спроса только после того, как видно, какой сегмент внёс вклад. Страница не должна обещать причинный ответ: она показывает место для разбора.

Спросите, кто читает страницу, по понедельникам или каждый день, какую величину считает тревожным отклонением и что делает при тревоге. Для еженедельного решения достаточно обновления после закрытия недели. Обновлять цифру каждую минуту здесь бесполезно: руководитель не принимает решение так часто. Если ему нужна поштучная проверка крупных бронирований, таблица деталей должна быть доступна, но не занимать весь первый экран.

Вторая часть договора — право сказать «данных недостаточно». В учебной таблице есть стоимость брони, но нет возвратов, признания выручки и маркетингового канала. Поэтому карточка называется «сумма оформленных бронирований», а не «чистая выручка» и не «эффективность маркетинга». Такое точное название предотвращает дорогой спор после публикации.

Данные: одна строка — одно бронирование

В базе «Авиаперевозки» таблица bookings хранит одну строку на book_ref. У неё есть дата book_date и полная сумма total_amount в рублях. База — учебная производная от демо-базы Postgres Professional; даты перенесены в август 2026 года и записаны в московском времени без часового пояса. Мы берём полную неделю 3–9 августа и сравниваем с 27 июля — 2 августа. Срез данных заканчивается позже, 11 августа в 18:00, поэтому обе недели уже закрыты.

В одном бронировании может быть несколько билетов. Прямое соединение bookings с tickets превратит одно денежное событие в несколько строк и завысит сумму. Для разбивки по числу билетов сначала посчитайте билеты по book_ref, затем присоедините одну строку результата к одной брони. Если позднее захотите разложить стоимость по маршрутам, понадобится отдельное правило распределения денег: билет и рейс не дают его автоматически.

Минимальный контракт данных для страницы
ОбъектЗерноНужное полеЧто проверить
bookingsОдна строка = одна броньbook_ref, book_date, total_amountУникальность ключа и сумма за закрытую неделю
ticketsОдна строка = один билетbook_ref, ticket_noЧисло билетов агрегируется до брони
КалендарьОдин день МСКПолуоткрытый интервалГраница в 00:00 не попадает в две недели

Четыре KPI-карточки и их проверяемый запрос

В верхней полосе поставьте сумму оформленных бронирований за неделю — 3 377 874 800 ₽, число бронирований — 42 561, среднюю сумму одной брони — 79 365,49 ₽ и изменение суммы к предыдущей полной неделе — +8,39%. Предыдущая неделя дала 3 116 503 800 ₽ на 39 216 бронях, среднюю сумму 79 470,21 ₽. Изменение числа броней составляет около +8,53%, среднего чека — около −0,13%; арифметически рост общей суммы почти целиком связан с числом броней, но это ещё не объяснение причины роста спроса.

Подписывайте и величину, и период: «Сумма новых бронирований, 3–9 августа, ₽». Не пишите «продажи сегодня» на недельном отчёте. Карточка изменения должна показывать базу сравнения рядом с процентом; иначе +8,39% не говорит читателю, с чем сравнили. Отсутствие возвратов и оплаты означает, что сумму нельзя трактовать как чистый денежный поток.

Проверьте изменение двумя способами. Прямой расчёт (3 377 874 800 / 3 116 503 800 - 1) × 100 даёт около 8,39%. Разложение общей суммы на число и среднюю стоимость показывает, почему один процент нельзя автоматически назвать «ростом чека»: броней стало больше на 3 345, а средняя сумма снизилась примерно на 104,72 ₽. На панели лучше поставить рядом относительное изменение и абсолютную прибавку 261 371 000 ₽. Если читать только проценты, маленькая база прошлого периода или ошибка выгрузки останутся невидимыми.

Итоговые карточки не нужно считать четырьмя независимыми запросами с разными фильтрами. Создайте один проверенный слой дневных или недельных агрегатов и вычисляйте доли от него. При изменении даты один фильтр должен менять все четыре карточки. Если возвращается пустой период, выводите «данных нет», а не 0 ₽: ноль означает измеренное отсутствие броней, пустота — отсутствие измерения. Это различие становится критичным при сбое загрузки.

Контроль итоговых карточек
НеделяБронированияСумма, ₽Средняя бронь, ₽
27.07–02.0839 2163 116 503 80079 470,21
03.08–09.0842 5613 377 874 80079 365,49
sqlЧетыре KPI: запрос к бронированиям за две полные недели
SELECT CASE WHEN book_date >= TIMESTAMP '2026-08-03'
            THEN 'текущая' ELSE 'предыдущая' END AS неделя,
       COUNT(*) AS бронирования,
       SUM(total_amount) AS сумма_руб,
       ROUND(AVG(total_amount), 2) AS средняя_бронь_руб
FROM bookings
WHERE book_date >= TIMESTAMP '2026-07-27'
  AND book_date < TIMESTAMP '2026-08-10'
GROUP BY 1;

Динамика: линия показывает движение, а не причину

Недельная карточка скрывает форму изменения. За 3–9 августа сумма бронирований по дням выросла с 452,16 до 509,63 млн ₽; число броней — с 5 665 до 6 531. Для ежедневной динамики используйте линию, если важна последовательность дней, и подпишите единицу «млн ₽». Таблица под графиком или раскрытие деталей даст точные значения. Не строите линию по пяти случайным строкам из bookings: сначала агрегируйте деньги по дате.

Растущая линия внутри одной недели не доказывает эффект акции или продукта. Возможно, влияет день недели или перенос спроса. Для решения о вмешательстве понадобится сравнить те же дни прошлой недели и проверить доступность рейсов, цены и полноту загрузки. На нашем макете график отвечает только на вопрос «когда изменялась сумма», а следующий разрез — «в каких типах бронирования».

Сумма оформленных бронирований по дням, млн ₽

Дни августа 2026, московское время. Числа округлены для графика; запрос и таблицы используют точные рубли.

Млн ₽
sqlЕжедневная сумма, одна строка на день
SELECT CAST(book_date AS DATE) AS день,
       COUNT(*) AS бронирования,
       SUM(total_amount) AS сумма_руб
FROM bookings
WHERE book_date >= TIMESTAMP '2026-08-03'
  AND book_date < TIMESTAMP '2026-08-10'
GROUP BY 1 ORDER BY 1;

Разрез: одна бронь или несколько билетов

Один билет содержат 28 011 броней, вместе они дают 1 586 128 300 ₽. В 14 550 бронях есть два и больше билетов; их сумма — 1 791 746 500 ₽, то есть около 53% всей суммы недели. Этот разрез полезен: показывает, что меньшее число многобилетных броней даёт большую часть суммы. Он не говорит, почему неделя выросла; для этого нужен тот же разрез по предыдущей неделе.

Проверка предыдущего периода даёт для одного билета 25 799 броней на 1 460 759 800 ₽, для двух и более — 13 417 на 1 655 744 000 ₽. Прирост суммы одного билета — 125 368 500 ₽, нескольких — 136 002 500 ₽. Оба сегмента внесли близкий вклад. Без этого сравнения легко было бы объявить «виновником» самый крупный сегмент только потому, что он крупный. SQL сначала группирует билеты до book_ref, затем берёт деньги из bookings один раз.

Проверьте разрез на одном book_ref: в ticket_counts он встречается один раз независимо от количества строк в tickets. Если число броней после LEFT JOIN стало больше числа исходных броней, запрос не готов к публикации. Если оно стало меньше после INNER JOIN, часть броней потерялась из-за отсутствующих билетов. Оба отклонения надо вывести отдельно, а не скрывать в группе «прочее». Полная сумма сегментов должна вернуть 3 377 874 800 ₽; это быстрый арифметический тест, который ловит и потери, и размножение.

Когда руководитель увидит большую сумму у многобилетных броней, не называйте её автоматически «корпоративными продажами»: в данных нет признака корпоративного клиента. Тип брони — описательная группировка, достаточная для первого разреза. Для решения о тарифе понадобятся маршрут, класс, дата вылета и, возможно, условия возврата; соединения с ними потребуют отдельного правила распределения полной суммы.

Состав суммы без размножения JOIN
Тип брониПрошлая неделя, ₽Текущая, ₽Прирост, ₽
1 билет1 460 759 8001 586 128 300125 368 500
2+ билета1 655 744 0001 791 746 500136 002 500
Сумма бронирований по числу билетов, млн ₽

Билеты агрегированы до брони; сумма каждой брони учитывается один раз.

Млн ₽
sqlДве недели по числу билетов: предварительная агрегация защищает сумму
WITH ticket_counts AS (
  SELECT book_ref, COUNT(*) AS ticket_count
  FROM tickets GROUP BY book_ref
)
SELECT CASE WHEN b.book_date >= TIMESTAMP '2026-08-03'
            THEN 'текущая' ELSE 'предыдущая' END AS неделя,
       CASE WHEN t.ticket_count = 1 THEN '1 билет'
            ELSE '2+ билета' END AS тип,
       COUNT(*) AS бронирования, SUM(b.total_amount) AS сумма_руб
FROM bookings b JOIN ticket_counts t USING (book_ref)
WHERE b.book_date >= TIMESTAMP '2026-07-27'
  AND b.book_date < TIMESTAMP '2026-08-10'
GROUP BY 1, 2 ORDER BY 1, 2;

Макет: сверху итог, ниже причина, затем проверяемые детали

Первый экран может состоять из четырёх карточек и одной широкой линии. Следующая строка — разбивка по одному и нескольким билетам; она объясняет состав, а не причинность. Ниже — таблица броней с датой, кодом, суммой и числом билетов. Так читатель начинает с ответа на свой вопрос, при необходимости спускается на уровень проверки, а не ищет главную цифру между шестью диаграммами.

Составьте макет на бумаге до переноса в BI. Для каждой зоны подпишите не название визуала, а вопрос, который он закрывает. Если зона не ведёт к решению и не помогает проверить число, её можно убрать. На телефоне карточки лягут одна под другую; порядок сверху вниз должен сохранять смысл. Не превращайте таблицу деталей в огромный скрин из десятков столбцов — оставьте ссылку на выгрузку или отдельный вопрос.

Макет недельной страницы
ЗонаВопросЭлементИсточник
ВерхВыросла ли сумма?4 KPI: сумма, число, средняя, изменениеbookings
СерединаКогда менялась?Линия по днямbookings, GROUP BY день
НижеКаков состав и вклад?2 столбца и таблица сравненияbookings + tickets, после агрегации
ДеталиМожно ли сверить?Брони по ключу и датеbookings + ticket_count

Фильтры и периоды: меньше свободы, больше сопоставимости

Оставьте переключатель полной недели и, если заказчик действительно принимает отдельное решение по типу брони, один фильтр «один билет / несколько». Для текущей неполной недели нужен отдельный режим с крупной пометкой о свежести. Не ставьте бесконечный диапазон дат рядом с карточкой «к прошлой неделе»: при произвольном промежутке база сравнения становится неоднозначной.

Синхронизируйте один и тот же период на всех элементах. Иначе верхняя сумма за календарную неделю, линия за семь скользящих дней, а таблица по локальному часовому поясу покажут три верных по отдельности, но несопоставимых ответа. Проверьте границу в полночь и дату 9 августа 23:59:59 на тестовой строке. Полуоткрытый интервал >= 03.08 00:00 и < 10.08 00:00 устраняет двойное попадание на границе.

Проверьте сценарий, когда пользователь выбирает только брони с одним билетом. Процент к прошлой неделе должен пересчитываться на той же группе и обеих полных неделях. Нельзя оставить в знаменателе все прошлые брони и показать результат как изменение однобилетных. В подписях графиков должен отображаться активный фильтр; при выгрузке в PDF или скриншот он иначе потеряется. Для публикации можно зафиксировать стартовый вид «все брони», чтобы два руководителя обсуждали одно и то же значение.

Отдельно решите, что происходит с календарём на границе часовых поясов. Учебный файл уже хранит московское время, но в рабочей системе timestamps часто записываются в UTC. Тогда переводите к зоне бизнеса до группировки по дню, а не после. В противном случае несколько часов около полуночи перейдут в соседний период; итоговая сумма за две недели может совпасть, но дневные графики и недельное сравнение разойдутся.

Как принять работу: сверка до красоты

Сначала сравните сумму и число броней из BI с независимым запросом к bookings без соединений. Затем убедитесь, что сумма сегментов точно равна общей сумме 3 377 874 800 ₽ и что дневные суммы складываются в ту же величину. Проверьте пустой сегмент, дубли book_ref, пропуски даты и суммы. На примере крупной брони раскройте путь от строки источника до карточки. Только после этого подбирайте подписи и интервалы оси.

Следующий тест — действия заказчика. Попросите руководителя за 30 секунд ответить, выросла ли сумма, за счёт объёма или размера брони, и где открыть детали. Если ответ требует вашего устного объяснения, заголовок или порядок элементов не работают. Если пользователь называет сумму «выручкой», вернитесь к подписи: экран подталкивает к неверному выводу. В приёмке фиксируйте не только пиксели, но и эти проверяемые ответы.

Запишите результаты приёмки как набор инвариантов: семь дневных строк; сумма дней равна карточке; сумма групп равна карточке; число броней после сегментации равно 42 561; предыдущая и текущая неделя не пересекаются; средняя равна сумме, делённой на число. Такой список можно выполнять заново после обновления источника. Для больших систем автоматизируйте его; для первого небольшого проекта достаточно сохранённых контрольных запросов и ответственного за их запуск.

Отдельная проверка — правдоподобие. Самая большая бронь учебной недели составляет 1 062 800 ₽; откройте её исходный ключ и убедитесь, что она попала в сумму один раз. Сравните медиану 56 000 ₽ со средней 79 365,49 ₽: длинный правый хвост предупреждает, что «типичную бронь» по средней описывать нельзя. Это не требование ставить все показатели на главный экран, а способ не допустить неподходящую интерпретацию.

Детали для ручной сверки, пять крупнейших броней
book_refДата МСКСумма, ₽Билеты
D7E9AA04.081 062 8004
60061E05.08910 6004
C72D7C07.08872 9003
91BC5C05.08809 1004
5D307106.08803 8004
sqlПять крупных броней для точечной проверки карточки
WITH ticket_counts AS (
  SELECT book_ref, COUNT(*) AS ticket_count
  FROM tickets GROUP BY book_ref
)
SELECT b.book_ref, CAST(b.book_date AS DATE) AS день,
       b.total_amount AS сумма_руб, t.ticket_count AS билеты
FROM bookings b JOIN ticket_counts t USING (book_ref)
WHERE b.book_date >= TIMESTAMP '2026-08-03'
  AND b.book_date < TIMESTAMP '2026-08-10'
ORDER BY b.total_amount DESC, b.book_ref LIMIT 5;

Публикация: доступ, обновление и след ошибки

Назначьте владельца определения метрики и владельца загрузки. На странице должна быть дата и время последнего успешного обновления, а не время, когда пользователь открыл вкладку. Если загрузка не прошла, оставьте прошлую версию с предупреждением; пустую или частичную неделю нельзя молча выдавать за новое состояние. Настройте права по ролям: детальные бронирования могут требовать более узкого доступа, чем агрегированные карточки.

Опишите поведение при исправлении прошлого периода: пересчитать обе недели, обновить процент и сохранить отметку об изменении. В учебной Parquet-базе нет живого расписания загрузок — здесь это критерии для будущей системы, а не обещание, что макет обновляется автоматически. Если отчёт будут экспортировать, сохраните в выгрузке период, единицу и дату данных; цифры без контекста быстро начинают жить отдельно от определения.

На опубликованной странице полезны три даты: конец периода расчёта, время последнего успешного обновления и, если цифры пересчитывались задним числом, дата корректировки. Не сливайте их в одну подпись «обновлено сегодня». Например, панель могла загрузиться сегодня утром, но показывать полную неделю, закрытую в воскресенье; для недельного решения это ожидаемо. Если загрузка частичная, зелёная отметка свежести без контроля числа строк лишь маскирует проблему. В регламенте укажите, кто обнаруживает сбой, кто перезапускает расчёт и как пользователи узнают об исправлении.

Где собрать: Excel, DataLens, Power BI, Superset или Metabase

Выбор начинается с источника, доступа и процесса обновления. Excel подходит небольшой команде и ручной проверке, но совместная публикация и единые определения требуют дисциплины. DataLens описывает подключение, датасеты, чарты и дашборды. Power BI разделяет отчёт в Desktop и дашборд в сервисе. Superset ориентирован на датасеты, Explore и SQL Lab. В Metabase сохранённый вопрос можно добавить на дашборд. Функции и интерфейс сверены по официальным страницам 27 сентября 2026 года; лицензии и доступность уточняйте отдельно.

Ни один из инструментов не исправит отсутствие определения «суммы бронирований». Сначала обеспечьте один слой проверенных агрегатов, затем выберите среду, где его смогут обновлять и обсуждать ваши пользователи. Ниже — роль инструмента в этом сценарии, а не рейтинг «лучших BI».

Выбор среды для этого кейса
СитуацияКуда смотретьПочемуКогда не подходит
Одна команда, разовая проверкаExcelБыстро сверить таблицу и сводныеНет устойчивого процесса обновления
Команда в экосистеме Yandex CloudDataLensПодключение → датасет → чарт → экранПроверьте доступы и источник
Используется модель Power BIPower BIОтчёт и сервисная публикацияУточните условия доступа и лицензии
Инженерная команда, SQL и своё размещениеSupersetДатасеты, чарты, SQL LabНужен владелец эксплуатации
Нужен быстрый вопрос к БДMetabaseКонструктор и SQL-вопросыПроверьте права на детальные данные

Через месяц: оставить только работающие элементы

Посмотрите, кто открывал страницу, какие фильтры применялись, какие выгрузки всё ещё просят вручную. Нулевая посещаемость сама по себе не доказывает плохой интерфейс: возможно, решение больше не принимают еженедельно. Спросите заказчика, какое действие он сделал по странице за месяц и чего ему не хватило. Если главная карточка стала спорной, исправьте определение и историю расчёта прежде, чем добавлять новые чарты.

Запишите срок пересмотра и критерий удаления. Дашборды обычно растут без ограничения: каждый новый вопрос превращается в ещё один блок. Разовый вопрос лучше решить отчётом; регулярный, но чужой аудитории — отдельной страницей. Так у первой страницы сохраняется один пользователь, одно решение и понятная иерархия.

Сохраните журнал изменений страницы: дату, формулировку показателя, причину правки и затронутые периоды. Когда у команды возникнет вопрос о старом решении, эта запись поможет отделить изменение бизнеса от изменения расчёта. Без истории даже правильная новая цифра выглядит как ошибка.

Восемь ошибок, которые делают дашборд опасным

Первая — назвать стоимость оформленных броней выручкой: руководитель примет решение о деньгах по показателю до возвратов и признания. Вторая — соединить bookings с tickets до суммирования: брони с несколькими билетами попадут в сумму повторно. Третья — смешать полную прошлую неделю с текущей неполной: страница нарисует ложное падение. Четвёртая — дать фильтр, который меняет только один график: пользователь сравнит несопоставимые числа. Пятая — скрыть время загрузки: старые данные будут выглядеть текущими.

Шестая — собрать страницу ради всех отделов сразу, поэтому ни один не увидит свою очередь действий. Седьмая — показать рост без базового периода и абсолютной суммы: +8,39% может оказаться на очень маленькой базе. Восьмая — сделать столбцы без нулевой точки и визуально преувеличить отличие дней. Каждая ошибка ведёт к конкретному неверному действию, поэтому проверяйте макет вопросом: «какое решение здесь может испортиться?»

Частые вопросы и следующий шаг

Как сделать дашборд без программиста? Для небольшой проверенной таблицы начните с Excel или конструктора BI; всё равно нужен человек, который знает зерно, формулы и источник. Сколько графиков должно быть? Столько, сколько нужно для одного решения, обычно немного; фиксированного отраслевого числа нет. Как часто обновлять? По частоте решения и задержке источника, а не по возможностям инструмента. Можно ли взять шаблон? Да, как сетку расположения, но определения метрик и контроль чисел придётся сделать для своих данных.

Возьмите свой повторяющийся вопрос и соберите одну страницу на бумаге: четыре подписанные карточки, один временной ряд, один объясняющий разрез и таблицу проверки. Затем выполните контрольный SQL. Если запрос пока сложен, начните с тренажёра SQL с нуля: на понятных данных легче обнаружить ошибку зерна, чем на готовой красивой панели.

Куда идти дальше по теме BI

Этот хаб отвечает на последовательность работы. Если сначала нужно договориться о значении показателя, откройте KPI и техническое задание. Если хочется понять разницу между платформой и экраном — BI-система и что такое дашборд. Для графиков пригодятся выбор диаграммы, принципы визуализации и визуализация в Python.

Для организации работы — BI-аналитик и собеседование BI-аналитика. Для контроля после запуска — почему дашборд не работает. ИИ может помогать черновиками, но проверку оставляйте за человеком: отдельно разобраны ИИ в BI, нейросеть для графиков и нейросеть для Excel. Практический путь в Excel: сводные таблицы → дашборд → повторяемая подготовка в Power Query. Для работы в BI откройте Yandex DataLens, Power BI и формулы DAX для модели с мерами. Если начинаете с SQL и готового источника, сравните Apache Superset и Metabase: во всех пяти гайдах использована та же учебная неделя и одна контрольная сумма.

Продолжить чтение
Вся библиотека