§ P15 — DAX · Справочник

DAX для управленцев: 15 формул для 80% задач

Бизнес-вопрос · Формула · Грабли

Формулы, без которых не обходится управленческая отчётность: YTD, YoY, план-факт, % от общего, rank, running average, прогноз. Каждая — с бизнес-вопросом, DAX-кодом и типичной ошибкой. Подходит как бриф для финдиректора и шпаргалка для разработчика.

У DAX есть репутация сложного языка. Справедливо: контексты фильтров, время вычислений, взаимодействие с моделью — там есть куда закапываться. Но для 90% управленческой отчётности достаточно 15-20 формул, которые закрывают типовые бизнес-вопросы.

Эта статья — справочник для двух аудиторий: финдиректор/BI-лид, который хочет понимать, что просит у разработчика; и junior-аналитик, которому нужна шпаргалка production-формул. Каждая формула — с разбором бизнес-вопроса и типичной ошибки (которую мы видим на аудитах снова и снова).

Допущения по модели: есть fact_sales (order_date, выручка, cogs, customer_id, product_id, region_id), dim_date (помечена как Date Table), dim_product, dim_region. Базовые меры [Revenue] и [COGS] уже определены через SUM.

Блок 01 · Time intelligence

01 · YTD (Year-to-Date)

Выручка с начала года

«Сколько мы продали с 1 января по текущую дату?»

Revenue YTD =
TOTALYTD(
    [Revenue],
    dim_date[date]
)

TOTALYTD возвращает сумму с начала календарного года до текущего контекста даты. Если ваш финансовый год не совпадает с календарным (например, начинается 1 апреля), добавьте третий аргумент: "31/03" — конец финансового года.

Грабли: работает только при правильно помеченной Date Table (Model → Mark as date table, выбрать колонку с датой). Без этого тихо выдаёт пустые значения.
02 · YoY (Year-over-Year)

Изменение к прошлому году

«Как изменилась выручка по сравнению с тем же периодом год назад?»

Revenue LY =
CALCULATE(
    [Revenue],
    SAMEPERIODLASTYEAR(dim_date[date])
)

Revenue YoY % =
DIVIDE(
    [Revenue] - [Revenue LY],
    [Revenue LY]
)

SAMEPERIODLASTYEAR сдвигает контекст даты ровно на год назад. Если смотрите на январь 2026 — показывает январь 2025.

Грабли: SAMEPERIODLASTYEAR работает с непрерывным диапазоном. Если в фильтре «Q1 + Q3 текущего года», результат может удивить. Для сложных периодов используйте DATEADD с явным указанием единицы.
03 · MTD / QTD

С начала месяца / квартала

«Сколько с начала этого месяца? С начала квартала?»

Revenue MTD =
TOTALMTD([Revenue], dim_date[date])

Revenue QTD =
TOTALQTD([Revenue], dim_date[date])

Симметричны TOTALYTD, но за месяц и квартал соответственно. Очень востребованы в операционных дашбордах, где следят за внутримесячной динамикой.

04 · Rolling 12 months

Сумма за последние 12 месяцев (скользящее)

«Какая у нас выручка за последний год — не YTD, а скользящий год к текущей дате?»

Revenue R12M =
CALCULATE(
    [Revenue],
    DATESINPERIOD(
        dim_date[date],
        MAX(dim_date[date]),
        -12,
        MONTH
    )
)

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

05 · Previous Period

Предыдущий период (месяц, квартал, год)

«А как было в прошлом месяце? В прошлом квартале?»

Revenue PM =
CALCULATE(
    [Revenue],
    PREVIOUSMONTH(dim_date[date])
)

Revenue PQ =
CALCULATE(
    [Revenue],
    PREVIOUSQUARTER(dim_date[date])
)

PREVIOUSMONTH/PREVIOUSQUARTER/PREVIOUSYEAR — готовые функции для сдвига на один период назад. Быстрее и читаемее, чем самодельные конструкции через DATEADD.

Грабли: эти функции возвращают весь предыдущий период. Если сейчас 15 апреля и вы смотрите MTD-значение, Previous Month вернёт сумму за весь март, а не за 1-15 марта. Для корректного сравнения MTD с предыдущим — используйте DATESMTD + DATEADD(-1, MONTH).

Блок 02 · Сравнения и доли

06 · % от общего

Доля в общей сумме

«Какую долю в выручке занимает каждая категория?»

Revenue % of Total =
DIVIDE(
    [Revenue],
    CALCULATE(
        [Revenue],
        REMOVEFILTERS(dim_product[category])
    )
)

Знаменатель — выручка без фильтра по категории (всё остальное сохранено). Делим текущую выручку на общий итог.

Грабли: если использовать ALL(dim_product) вместо REMOVEFILTERS по конкретной колонке — снимутся все фильтры на dim_product, включая бренд, подкатегорию. Доля посчитается некорректно. См. пуск про REMOVEFILTERS vs ALL.
07 · Gross Margin %

Маржа и её процент

«Какая маржинальность по категориям? Какой абсолютный margin contribution?»

Gross Margin =
[Revenue] - [COGS]

Gross Margin % =
DIVIDE(
    [Revenue] - [COGS],
    [Revenue]
)

Базовая мера для финансовой отчётности. Обычно комбинируется с % от общего и YoY — получается полноценный margin breakdown.

08 · Variance % (отклонение)

Процент изменения между двумя величинами

«На сколько процентов факт отличается от плана? Или от прошлого периода?»

// Универсальная форма
Variance % =
DIVIDE(
    [Actual] - [Baseline],
    ABS([Baseline])
)

// Пример для план-факт
Variance Plan-Fact % =
DIVIDE(
    [Revenue] - [Revenue Plan],
    ABS([Revenue Plan])
)

ABS в знаменателе важен: если базовый уровень может быть отрицательным (убыток, затраты), без ABS знак вариации получится противоположным от интуитивного.

09 · Share of Segment

Доля внутри группы

«Какая доля продукта внутри своей категории?»

Revenue % of Category =
DIVIDE(
    [Revenue],
    CALCULATE(
        [Revenue],
        REMOVEFILTERS(dim_product[product_name])
    )
)

Отличается от формулы 06 тем, что снимается фильтр только на уровне продукта. Фильтр по категории сохраняется, поэтому знаменатель — это выручка всех продуктов в текущей категории.

Полезно для дерева долей: % в категории × % категории в общем = % продукта в общем.

Блок 03 · Ранжирование и top-N

10 · RANKX

Место в рейтинге

«Какое место у этого региона по выручке?»

Region Rank =
RANKX(
    ALL(dim_region),
    [Revenue],
    ,
    DESC,
    DENSE
)

Четвёртый аргумент — направление (ASC/DESC). Пятый — как обрабатывать одинаковые значения: SKIP (пропускать номера: 1,2,2,4) или DENSE (без пропусков: 1,2,2,3). Для управленческих отчётов обычно DESC + DENSE.

Грабли: ALL(dim_region) без учёта контекста может давать глобальный ранг, даже когда нужен ранг внутри категории или фильтра. Для сложных случаев используйте ALLSELECTED.
11 · Top N + Others

Показать top-5, остальное свернуть в «Прочие»

«Покажите топ-5 продуктов по выручке, остальные одной строкой "Прочие"»

Top5 Revenue =
VAR _rank =
    RANKX(
        ALL(dim_product[product_name]),
        [Revenue],
        , DESC, DENSE
    )
RETURN
    IF(
        _rank <= 5,
        [Revenue],
        BLANK()
    )

Others Revenue =
CALCULATE(
    [Revenue],
    FILTER(
        ALL(dim_product),
        RANKX(
            ALL(dim_product[product_name]),
            [Revenue],
            , DESC, DENSE
        ) > 5
    )
)

Сложнее классического RANKX, но даёт возможность отрисовать на графике топ-5 отдельными столбцами плюс «Прочие» сумарно. Без этого паттерна визуал с 100+ продуктами выглядит нечитаемо.

12 · ABC-классификация

ABC по вкладу в общую сумму

«Разнесите все товары по классам A/B/C: A — первые 80% выручки, B — следующие 15%, C — оставшиеся 5%»

ABC Class =
VAR _total_revenue =
    CALCULATE(
        [Revenue],
        ALL(dim_product)
    )
VAR _cum_share =
    DIVIDE(
        CALCULATE(
            [Revenue],
            FILTER(
                ALL(dim_product),
                [Revenue] >= EARLIER([Revenue])
            )
        ),
        _total_revenue
    )
RETURN
    SWITCH(
        TRUE(),
        _cum_share <= 0.80, "A",
        _cum_share <= 0.95, "B",
        "C"
    )

Считает накопительную долю каждого товара в общей выручке и раскладывает по классам. Тяжёлый запрос для больших каталогов — на моделях >50 тыс. SKU имеет смысл выносить ABC-класс в ETL как заранее рассчитанную колонку в dim_product.

Блок 04 · План-факт и прогноз

13 · Plan vs Actual

Базовая мера план-факт

«Выполняем план по выручке или нет? На сколько отстаём/обгоняем?»

// предполагаем, что есть fact_plan с [plan_revenue]
Plan Fulfillment % =
DIVIDE(
    [Revenue],
    [Revenue Plan]
)

Plan Delta =
[Revenue] - [Revenue Plan]

Plan Status =
SWITCH(
    TRUE(),
    [Plan Fulfillment %] >= 1.0, "✓ План выполнен",
    [Plan Fulfillment %] >= 0.9, "⚠ Близко",
    "✗ Провал"
)

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

Грабли: план и факт должны быть привязаны к одной гранулярности по времени (месяц/квартал). Если план загружен годовой, а факт — по дням, деление даст бессмыслицу. Предобрабатывайте план до нужной гранулярности в ETL.
14 · Running Total

Накопительный итог с начала периода

«Как нарастает выручка с начала года по дням/неделям?»

Revenue Running =
CALCULATE(
    [Revenue],
    FILTER(
        ALL(dim_date),
        dim_date[date] <= MAX(dim_date[date])
    )
)

Стандартная накопительная сумма. Визуально — плавно растущая кривая, которая ярко показывает темп выполнения плана по году.

Добавьте рядом плановую накопительную (такой же running, но от [выручка Plan]) — и получите классический график CFO «факт против плана по нарастанию».

15 · Simple Forecast

Простой прогноз на остаток периода

«Если темп текущего месяца сохранится, куда придём к концу месяца?»

Forecast MTD to Month End =
VAR _days_passed =
    COUNTROWS(
        FILTER(
            dim_date,
            dim_date[date] <= TODAY()
                && MONTH(dim_date[date]) = MONTH(TODAY())
                && YEAR(dim_date[date]) = YEAR(TODAY())
        )
    )
VAR _days_total =
    DAY(EOMONTH(TODAY(), 0))
VAR _mtd_revenue = [Revenue MTD]
RETURN
    DIVIDE(_mtd_revenue, _days_passed) * _days_total

Берёт выручку с начала месяца, делит на прошедшие дни, умножает на длину всего месяца. Получается наивный прогноз на конец месяца при сохранении текущего темпа. Грубо, но для операционного контроля работает — главное, что сигнал виден заранее, а не 1-го числа следующего месяца.

Грабли: для сезонных бизнесов (ритейл, HoReCa) простая линейная экстраполяция сильно врёт. Для них лучше брать профиль прошлогодних последних дней и умножать на YoY-коэффициент первой половины текущего месяца.

Как запомнить и где применять

Этими 15 формулами закрывается бо́льшая часть управленческих отчётов среднего бизнеса: P&L по периодам, дашборды продаж, операционные сводки, план-факт. Держите шпаргалку под рукой — в DAX Cheat Sheet собрано то же самое + ещё 10 формул для HR, закупок, финансового моделирования. Файл можно распечатать и положить рядом с монитором.

Для освоения хватит пары вечеров практики: возьмите свою модель, прогоните по ней каждую формулу из списка. После этого вопросы «как посчитать X» начинают решаться сами.

Если видите, что готовые формулы работают медленно — прочитайте P13 про рефакторинг Power BI: там подробно про VAR, REMOVEFILTERS, bi-directional и остальные ускоряющие паттерны. Многие проблемы производительности — это не «формула неправильная», а «формула написана без учёта того, как движок её исполняет».

Что делать дальше

  • Для внутренней команды — скачайте DAX Cheat Sheet, распечатайте, раздайте аналитикам. Сэкономит им часы поиска по документации.
  • Если нужно обучение — проводим 2-3 сессии по DAX и SSAS для вашего сотрудника. Формат — практика на вашей реальной модели. 50-100 тыс. ₽ в зависимости от объёма.
  • Если отчёты тормозят после появления новых формул — 5-дневный аудит найдёт проблемные меры и даст план рефакторинга.

Связанные материалы:

§ Шпаргалка · PDF

DAX Cheat Sheet
для команды

25 production-формул для управленческой аналитики: time intelligence, план-факт, ABC, прогнозы, RLS-хелперы. С пометками о граблях.

Телефон+7 918 042 34 43