В DAX два вида контекста, и путаница между ними — источник большинства «почему считается не то». Один — контекст фильтра — разберём в следующем уроке. Этот урок про второй: контекст строки (row context). Объясняем по визуальному разбору SQLBI.
Прожектор на одной строке
Контекст строки — это указатель на одну конкретную строку таблицы. Представьте прожектор, который светит ровно на один ряд: «вот эта строка — текущая».
Зачем он нужен? Без него выражение Продажи[Количество] * RELATED ( Товары[Цена] ) бессмысленно — движок не знает, из какой строки брать количество. Контекст строки отвечает на вопрос «а какая строка сейчас?».
Контекст строки говорит: «вот текущая строка, бери значения её столбцов». Без него ссылка на столбец не имеет смысла.
Где он возникает
Контекст строки появляется ровно в двух местах.
1. Вычисляемый столбец. При обновлении модели движок проходит таблицу строка за строкой и вычисляет формулу для каждой:
Сумма строки = -- расчётный столбец в Продажи
Продажи[Количество] * RELATED ( Товары[Цена] )
Для каждой строки Продажи прожектор стоит на ней, и Количество берётся из этой строки.
2. Итераторы. Функции с буквой X (SUMX, AVERAGEX) и табличные (ADDCOLUMNS, SUMMARIZE) проходят таблицу построчно — каждый шаг создаёт контекст строки:
Выручка = SUMX ( Продажи, Продажи[Количество] * RELATED ( Товары[Цена] ) )
SUMX светит прожектором на каждую строку по очереди, считает выражение и складывает.
Контекст строки ≠ контекст фильтра
Их легко перепутать, но они делают разное:
- Контекст фильтра решает, какие строки вообще видны (срезы, фильтры, ячейка визуала);
- Контекст строки перебирает строки и даёт доступ к значениям столбцов текущей.
Формула SQLBI: «контекст фильтра фильтрует, контекст строки итерирует». Сначала фильтр оставляет видимые строки, потом итератор бежит по ним, создавая для каждой контекст строки.
Важно: меры игнорируют контекст строки
Вот тонкость, на которой спотыкаются все.
- Ссылка на столбец (
Продажи[Количество]) требует контекст строки — она про «значение в этой строке». - Ссылка на меру (
[Выручка]) контекст строки игнорирует — мера несёт свою логику и возвращает агрегат, ей не нужна «текущая строка».
Поэтому вычисляемый столбец = Продажи[Количество] работает (есть строка), а = [Выручка] в столбце вернёт не «выручку этой строки», а нечто другое — мера не реагирует на прожектор сама по себе. Что происходит, когда мера всё-таки оказывается внутри контекста строки, — тема урока про переход контекста.
Ждать, что мера внутри SUMX посчитается «по текущей строке» просто потому, что строка есть. Сама по себе — нет: меры не видят контекст строки. Нужен механизм, который превратит строку в фильтр (переход контекста).
Сколько строк переберёт итератор
Контекст строки создаёт та таблица, которую вы передали итератору, — и её размер решает, сколько раз выполнится выражение:
SUMX ( Продажи, ... )— по всем строкам продаж;SUMX ( VALUES ( Продажи[НомерЗаказа] ), ... )— по уникальным заказам (строк меньше).
Разная таблица — разное число итераций и, бывает, разный результат. Выбор таблицы для итератора — это выбор грануляции расчёта.
Что дальше
Контекст строки — «текущая строка» в столбцах и итераторах. Дальше — контекст фильтра: то, что определяет, какие строки вообще видны мере. А потом свяжем их вместе в уроке про переход контекста.