Урок 19 · 8 мин чтения

Переход контекста (context transition)

Как текущая строка превращается в фильтр — механизм, который связывает контекст строки и контекст фильтра. Самое «магическое» место DAX.

Мы разобрали два контекста: строки (текущая строка в итераторе) и фильтра (что видно мере). В прошлом уроке прозвучало: меры игнорируют контекст строки. Но тогда почему AVERAGEX(VALUES(Продажи[НомерЗаказа]), [Выручка]) считает выручку по каждому заказу? Ответ — переход контекста. Это и есть мост между двумя контекстами.

В чём идея

Переход контекста (context transition) — это превращение текущей строки в эквивалентный фильтр. Его запускает CALCULATE — а также любая мера (потому что мера неявно обёрнута в CALCULATE).

Когда CALCULATE срабатывает внутри контекста строки, он берёт текущую строку и накладывает её как фильтр: «оставь только эту строку (и всё, что с ней связано)». Дальше выражение считается уже в этом новом контексте фильтра.

Одной фразой

CALCULATE (и любая мера внутри итератора) превращает «текущую строку» в фильтр. Контекст строки → контекст фильтра. Поэтому мера, оказавшись в итераторе, вдруг начинает считаться «по строке».

Почему средний чек работает

Вернёмся к примеру:

Средний чек =
AVERAGEX ( VALUES ( Продажи[НомерЗаказа] ), [Выручка] )

Пошагово:

  1. VALUES даёт список уникальных заказов; AVERAGEX идёт по ним — это контекст строки (текущий заказ);
  2. встречается мера [Выручка] — она неявно CALCULATE, поэтому срабатывает переход контекста: текущий заказ становится фильтром;
  3. [Выручка] считается только по этому заказу;
  4. AVERAGEX усредняет суммы заказов.

Без перехода контекста [Выручка] вернула бы общий итог в каждой итерации, и среднее было бы бессмысленным. Именно переход делает расчёт правильным.

Вычисляемый столбец и CALCULATE

Тот же эффект в вычисляемом столбце. Просто [Выручка] в столбце игнорирует строку (вернёт общий итог). А обёрнутая в CALCULATE — «прижимается» к строке:

Выручка по этой строке =          -- расчётный столбец
CALCULATE ( [Выручка] )

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

Чем это объясняет «несходящийся итог»

Помните, что итог в таблице иногда не равен сумме строк? Часть таких случаев — как раз переход контекста: в каждой строке мера считается со своим «строчным» фильтром, а в «Итого» — без него. Для суммы совпадёт, для среднего/доли — нет. Это не баг, а следствие того, как строка превращается в фильтр.

Переход контекста стоит дорого

Каждая итерация с мерой внутри запускает CALCULATE и переход контекста — на больших таблицах это ощутимая нагрузка. SUMX(Продажи, [КакаяТоМера]) на миллионах строк может быть медленным. Если можно посчитать без меры внутри итератора (на столбцах) — так дешевле.

Когда это включается — короткий список

Переход контекста срабатывает, если одновременно есть контекст строки и вызов CALCULATE (явный или неявный через меру):

  • мера внутри итератора (SUMX(T, [Мера]));
  • CALCULATE(...) в вычисляемом столбце;
  • мера, ссылающаяся на другую меру внутри ADDCOLUMNS/SUMMARIZE.

Нет контекста строки (обычная мера в визуале) — перехода нет, считается как есть.

Что дальше

Три кита DAX собраны: контекст строки, контекст фильтра и переход между ними. На этом фундаменте держится всё остальное. Дальше в курсе — фильтрующие функции, логика, связи и работа со временем.

Почему `[Выручка]` внутри `AVERAGEX(VALUES(Продажи[НомерЗаказа]), [Выручка])` считается по каждому заказу, хотя меры игнорируют контекст строки?
Любая мера неявно содержит CALCULATE, а CALCULATE в контексте строки запускает переход контекста: текущий заказ превращается в фильтр, и [Выручка] считается только по нему.
Прогресс сохраняется в вашем браузере.
§ Power BI под ключ

Нужно внедрить
это в компании?

Соберём DWH, модель и дашборды под ваши данные. Бесплатная консультация — 30 минут.

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