Основы DAX:
Вычисляемые Столбцы и Меры – Ваше Волшебство
в Мире Данных
Привет! Если вы когда-либо чувствовали себя потерянным среди моря цифр

пытаясь вытащить из них хоть какой-то смысл, то эта статья — ваш спасательный круг. Мы уже немного заглянули в мир DAX, поняли, чем он отличается от Excel, SQL и MDX. Теперь пришло время освоить его сердце, его пульс,
его саму суть – вычисляемые столбцы и меры. Это не просто термины; это ваши новые суперспособности,
которые превратят сырые данные в захватывающие истории и действенные инсайты.

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

Я обещаю, что к концу этой статьи вы не только поймете, что такое вычисляемые столбцы и меры, но и почувствуете, как DAX открывает перед вами двери в мир, где данные начинают говорить, а вы — их понимать. Вложите в чтение столько же сил, сколько я вложил в написание, и вы не пожалеете!
Глава 1: Вычисляемые Столбцы – Добавляем Новые Измерения к Вашим Данным

Начнем с чего-то знакомого, но с новым уровнем мощности. Вы когда-нибудь добавляли новый столбец в Excel, чтобы сделать расчет на основе других столбцов в той же строке? Например, "Общая стоимость = Цена * Количество"?
Вот это и есть суть вычисляемого столбца в DAX, но с гораздо большими возможностями и в масштабе, который Excel не может предложить.

Что это такое?

Вычисляемый столбец (Calculated Column) — это новый столбец, который вы добавляете в существующую таблицу вашей модели данных. Его значения вычисляются для каждой строки этой таблицы на основе формулы DAX. Эти значения затем сохраняются в модели данных, занимая память, и пересчитываются только при обновлении данных.

Как это работает? (Контекст Строки)

Когда вы создаете вычисляемый столбец, DAX проходит по каждой строке таблицы. Для каждой строки он "знает" значения всех столбцов в этой конкретной строке. Это называется контекстом строки (Row Context).
Формула вычисляемого столбца оперирует именно в этом построчном контексте.

Когда использовать Вычисляемые Столбцы?

Вычисляемые столбцы идеально подходят для:
1.     Категоризации или классификации данных: Создание новых атрибутов на основе существующих.
○       Пример: Разделение клиентов на "Высокодоходных" и "Обычных" на основе их общих трат.
○       Пример: Определение "Сезона" (Весна, Лето, Осень, Зима) на основе даты.
2.     Простых построчных расчетов: Когда вам нужно получить новое значение для каждой отдельной строки.
○       Пример: Расчет валовой прибыли для каждой строки заказа: [Sales Amount] - [Total Product Cost].
○       Пример: Объединение имени и фамилии в один столбец.
3.     Создания новых измерений: Если вы хотите использовать результат вычисления как фильтр или ось в отчете (например, "Возрастная Группа Клиента").

Примеры с AdventureWorks:
Оживляем данные!Давайте посмотрим, как вычисляемые столбцы могут преобразить ваши данные AdventureWorks.

Пример 1: Валовая Прибыль для каждой строки заказа
В таблице FactInternetSales (факты интернет-продаж) у нас есть SalesAmount (сумма продаж) и TotalProductCost (себестоимость). Мы хотим видеть валовую прибыль для каждой отдельной транзакции.
Gross Profit Per Order = FactInternetSales[SalesAmount] - FactInternetSales[TotalProductCost]


●       Что происходит: DAX берет каждую строку в FactInternetSales. Для первой строки он вычитает TotalProductCost из SalesAmount этой строки и сохраняет результат в Gross Profit Per Order. Затем переходит ко второй строке и так далее.
●       Применение: Теперь вы можете видеть прибыль по каждой транзакции, а также суммировать ее по любым измерениям (продуктам, клиентам, датам).

Пример 2: Полное Имя Клиента
В таблице DimCustomer (измерение клиентов) у нас есть FirstName и LastName. Давайте объединим их для удобства.
Full Name = DimCustomer[FirstName] & " " & DimCustomer[LastName]

●       Что происходит: Для каждой строки клиента DAX берет имя, добавляет пробел, затем добавляет фамилию.
●       Применение: Теперь у вас есть единый столбец для отображения имен клиентов в отчетах, что гораздо удобнее для пользователей.

Пример 3: Год Заказа
В таблице FactInternetSales есть столбец OrderDate.
Мы хотим извлечь только год, чтобы использовать его как простое измерение.
Order Year = YEAR(FactInternetSales[OrderDate])

●       Что происходит: Функция YEAR() извлекает год из даты для каждой строки.
●       Применение: Теперь вы можете легко фильтровать или группировать продажи по годам, даже если у вас нет отдельного измерения времени.

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

●       Статичность: Они вычисляются только при обновлении данных.
Если вам нужны динамические расчеты, которые меняются в зависимости от фильтров пользователя
(например, "продажи за текущий год"), вычисляемые столбцы не подойдут.
Глава 2: Меры – Динамическая Мощь Вашего Анализа

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

Что это такое?
Мера (Measure) — это формула DAX, которая выполняет агрегацию (суммирование, усреднение, подсчет) или другое вычисление над данными. В отличие от вычисляемых столбцов, значения мер не хранятся в модели данных.
Они вычисляются "на лету" каждый раз, когда вы их используете в отчете или визуализации.

Как это работает? (Контекст Фильтра)
Меры вычисляются в контексте фильтра (Filter Context). Это означает, что когда вы перетаскиваете меру в сводную таблицу, график или срез, DAX автоматически применяет все фильтры, которые активны в данный момент.
●       Если вы смотрите на общие продажи, мера покажет сумму по всем данным.
●       Если вы фильтруете по "Bikes", мера покажет сумму продаж только для велосипедов.
●       Если вы помещаете меру в строку сводной таблицы с "регионами" и в столбец с "годами", мера покажет продажи для каждого региона в каждом году.

Мера "знает", в каком "срезе" данных она находится, и адаптирует свое вычисление.
Это и есть сердце динамического анализа в DAX.

Когда использовать Меры?
Меры — это ваш основной инструмент для:
1.     Любых агрегаций: Суммы, средние, количества, минимумы, максимумы.
○       Пример: Total Sales = SUM(FactInternetSales[SalesAmount]).
○       Пример: Average Order Quantity = AVERAGE(FactInternetSales[OrderQuantity]).
2.     Динамических расчетов: Вычислений, которые должны адаптироваться к фильтрам пользователя.
○       Пример: Продажи за предыдущий год.
○       Пример: Процент роста продаж.
○       Пример: Скользящие средние.
3.     Ключевых показателей эффективности (KPI): Меры являются основой для всех бизнес-показателей, которые вы отслеживаете.

Примеры с AdventureWorks:
Создаем динамические показатели!
Давайте создадим несколько мер, чтобы почувствовать их мощь.

Пример 4: Общие Продажи
Это самая базовая и, возможно, самая часто используемая мера.
Total Sales = SUM(FactInternetSales[SalesAmount])

●       Что происходит: Функция SUM() суммирует значения в столбце SalesAmount из таблицы FactInternetSales.
●       Применение: Поместите эту меру в карточку Power BI, и вы увидите общую сумму продаж. Добавьте Product Category в таблицу, и мера Total Sales автоматически покажет продажи по каждой категории.
Это волшебство контекста фильтра!

Пример 5: Среднее Количество Заказанных Продуктов
Мы хотим узнать, сколько в среднем продуктов заказывают клиенты.
Average Order Quantity = AVERAGE(FactInternetSales[OrderQuantity])

●       Что происходит: Функция AVERAGE() вычисляет среднее значение столбца OrderQuantity.
●       Применение: Эта мера динамически покажет среднее количество продуктов в заказе для любого выбранного вами среза (по продукту, по клиенту, по дате).

Пример 6: Количество Уникальных Клиентов
Мы хотим подсчитать, сколько уникальных клиентов совершили покупки.
Unique Customers = DISTINCTCOUNT(FactInternetSales[CustomerKey])

●       Что происходит: Функция DISTINCTCOUNT() подсчитывает количество уникальных значений в столбце CustomerKey.
●       Применение: Эта мера покажет количество уникальных клиентов, которые соответствуют текущим фильтрам.

Агрегационные Функции:
Ваши первые шаги в DAX
Большинство мер начинаются с агрегационной функции.
Вот самые распространенные:

●       SUM(Column): Суммирует все числа в столбце.
●       AVERAGE(Column): Вычисляет среднее значение чисел в столбце.
●       COUNT(Column): Подсчитывает количество непустых значений в столбце.
●       COUNTROWS(Table): Подсчитывает количество строк в таблице.
●       MAX(Column): Находит максимальное значение в столбце.
●       MIN(Column): Находит минимальное значение в столбце.
●       DISTINCTCOUNT(Column): Подсчитывает количество уникальных значений в столбце.
Глава 3: Вычисляемые Столбцы vs. Меры: Когда и Что Использовать?

Это один из самых частых вопросов для новичков в DAX.
Выбор между вычисляемым столбцом и мерой — это не просто вопрос предпочтений, это вопрос производительности, гибкости и правильного моделирования данных.
Правило большого пальца:

●       Если вам нужно новое измерение (категория, группа), по которому вы будете фильтровать или группировать данные, и это значение не меняется в зависимости от других фильтров,
используйте Вычисляемый Столбец.

●       Если вам нужен новый показатель (числовое значение), который должен агрегироваться и динамически адаптироваться к фильтрам в отчете, используйте Меру.

Как часто говорят эксперты DAX, "почти всегда, если вы сомневаетесь, используйте меру. Вычисляемые столбцы следует использовать только тогда, когда это абсолютно необходимо, например, для создания нового измерения, которое не может быть получено другим способом".
Глава 4: Умные Вычисления с Переменными (VAR): Чистота и Эффективность

Когда ваши формулы DAX становятся сложнее, вы заметите, что некоторые промежуточные расчеты повторяются.
Это не только делает формулу громоздкой и трудночитаемой, но и может снизить производительность, так как DAX может пересчитывать одно и то же выражение несколько раз. Здесь на помощь приходят переменные (VAR).

Зачем нужны переменные?
Переменные в DAX — это как временные хранилища для результатов вычислений внутри одной формулы.
Они дают вам несколько ключевых преимуществ:
1.     Читаемость кода: Разбивают сложную формулу на более мелкие, осмысленные части.
·        Отладка: Позволяют легко проверить промежуточные результаты.
·        Производительность: DAX вычисляет переменную только один раз, даже если вы ссылаетесь на нее несколько раз в формуле. Это может значительно ускорить выполнение сложных мер.
·        Упрощение логики: Позволяют избежать повторения сложных выражений.

Синтаксис VAR и RETURN
Переменные определяются с помощью ключевого слова VAR, а затем используются в секции RETURN.
Measure Name =
VAR Variable1 = Expression1
VAR Variable2 = Expression2
RETURN
 Final_Expression_Using_Variables


Пример 7:
Процент продаж от общего итога с использованием переменных (AdventureWorks)
Давайте перепишем наш пример Sales % of Grand Total с использованием переменных, чтобы сделать его более читаемым.

Sales % of Grand Total (with VAR) =
VAR CurrentProductSales = SUM(FactInternetSales[SalesAmount])
VAR AllSales = CALCULATE(SUM(FactInternetSales[SalesAmount]), ALL(DimProduct))
RETURN
 DIVIDE(CurrentProductSales, AllSales, BLANK())


Разбор:
●       VAR CurrentProductSales = SUM(FactInternetSales[SalesAmount]): Мы сохраняем сумму продаж для текущего контекста (например, для конкретного продукта) в переменную CurrentProductSales.
●       VAR AllSales = CALCULATE(SUM(FactInternetSales[SalesAmount]), ALL(DimProduct)): Мы сохраняем общую сумму продаж по всем продуктам (игнорируя фильтры по продукту) в переменную AllSales.
●       RETURN DIVIDE(CurrentProductSales, AllSales, BLANK()): В секции RETURN мы используем эти переменные для вычисления процента.

Преимущество:
Формула стала гораздо более понятной. Легко увидеть, что мы делим "продажи текущего продукта" на "все продажи".
Глава 5: Защита Ваших Расчетов – Обработка Ошибок в DAX

Как и в любом языке программирования, в DAX могут возникать ошибки.
Самая распространенная и коварная — деление на ноль.
Если вы попытаетесь разделить число на ноль (например, SalesAmount / OrderQuantity, а OrderQuantity равно 0), DAX выдаст ошибку. Это может привести к появлению некрасивых ошибок в отчетах или к некорректным результатам.

Ключевые функции для обработки ошибок:
1.     DIVIDE(Numerator, Denominator, [AlternateResult]):
○       Это лучшая функция для деления в DAX. Она специально разработана для обработки деления на ноль.
○       Numerator: Числитель.
○       Denominator: Знаменатель.
○       [AlternateResult]: Необязательный аргумент. Значение, которое будет возвращено, если знаменатель равен 0 или пуст. Если не указан, возвращается BLANK().
2.     IFERROR(Value, Value_if_error):
○       Возвращает Value, если оно не содержит ошибки; в противном случае возвращает Value_if_error.
○       Менее предпочтительна для деления, чем DIVIDE, но полезна для других типов ошибок.
3.     BLANK():
○       Возвращает пустое значение. Часто используется как AlternateResult в DIVIDE или Value_if_error в IFERROR.

Пример 8:
Расчет Средней Стоимости Заказа с обработкой ошибок (AdventureWorks)
Мы хотим рассчитать среднюю стоимость заказа (Sales Amount / Order Quantity), но некоторые заказы могут иметь нулевое количество (например, заказы на услуги без товаров).

Average Order Value =
DIVIDE(
   SUM(FactInternetSales[SalesAmount]),
   SUM(FactInternetSales[OrderQuantity]),
   BLANK() -- Возвращаемпустоту, если OrderQuantity равно 0
)

●       Что происходит: DIVIDE безопасно выполняет деление. Если SUM(FactInternetSales[OrderQuantity]) равно 0 (или пусто), то вместо ошибки будет возвращено BLANK().
●       Применение: Ваши отчеты будут выглядеть чисто, без ошибок, и пользователи не будут сбиты с толку.
Глава 6: Строительные Блоки – Основные Типы Данных и Операторы DAX

Как и любой язык, DAX имеет свои типы данных и операторы, которые являются основой для построения формул.

Основные Типы Данных DAX:
DAX автоматически определяет тип данных, но полезно знать основные:
1.     Целое число (Integer): Целые числа без десятичных знаков (например, 1, 100, -5).
2.     Десятичное число (Decimal Number): Числа с десятичными знаками (например, 1.25, 3.14).
3.     Валюта (Currency): Специальный тип для денежных значений, с фиксированной точностью для предотвращения ошибок округления (например, $123.45).
4.     Булево (Boolean): TRUE или FALSE. Используется в логических выражениях.
5.     Дата/Время (Date/Time): Хранит дату и время. DAX имеет мощные функции для работы с датами.
6.     Строка (String): Текстовые значения (например, "Bikes", "North America").

Приведение типов (Type Coercion): DAX достаточно умён и часто автоматически преобразует типы данных, если это возможно (например, строку "10" в число 10 для арифметических операций). Однако, будьте внимательны, так как не всегда это происходит ожидаемым образом.

Операторы DAX: Ваш инструментарий для формул DAX использует стандартные операторы:
1.     Арифметические операторы:
○       + (сложение)
○       - (вычитание)
○       * (умножение)
○       / (деление)
○       ^ (возведение в степень)
2.     Операторы сравнения:
○       = (равно)
○       <> (не равно)
○       > (больше)
○       < (меньше)
○       >= (больше или равно)
○       <= (меньше или равно)
3.     Текстовый оператор (конкатенация):
○       & (объединение строк) – как в нашем примере Full Name.
4.     Логические операторы:
○       && (логическое И / AND)
○       || (логическое ИЛИ / OR)
○       IN (проверка вхождения значения в список)

Пример 9: Сложное логическое условие с операторами (AdventureWorks)
Мы хотим найти продажи для продуктов категории 'Bikes' И 'Clothing', которые были проданы в 2007 ИЛИ 2008 году.
Sales Bikes or Clothing 2007 or 2008 =
CALCULATE (
   SUM ( FactInternetSales[SalesAmount] ),
   ( 'Product'[Category] = "Bikes" || 'Product'[Category] = "Clothing" ) &&
   ( 'Date'[Calendar Year] = 2007 || 'Date'[Calendar Year] = 2008 )
)

Разбор:
●       Мы используем || для условия "ИЛИ" между категориями и между годами.
●       Мы используем && для условия "И" между группами условий.
●       Скобки важны для определения порядка выполнения логических операций.
Заключение: Ваш Путь к Мастерству DAX Начинается Сейчас!

Поздравляю! Вы только что сделали огромный шаг в освоении DAX.
Вы поняли, что такое вычисляемые столбцы и меры – два фундаментальных столпа, на которых строится вся аналитическая мощь DAX. Вы узнали, когда использовать каждый из них, как переменные делают ваш код чище
и быстрее, и как обрабатывать ошибки, чтобы ваши отчеты всегда были безупречны.
А также познакомились с базовыми типами данных и операторами.

Помните, что DAX — это не просто набор функций;
это новый способ мышления о данных. Он позволяет вам:
●       Превращать сырые данные AdventureWorks в значимые показатели.
●       Создавать динамические отчеты, которые адаптируются к вопросам пользователя.
●       Рассказывать убедительные истории с помощью чисел.

Ваш путь к мастерству DAX только начинается. Самое главное сейчас — практика. Откройте Power BI Desktop
(или Power Pivot в Excel), загрузите данные AdventureWorks и начните экспериментировать. Создавайте свои первые вычисляемые столбцы и меры, играйте с ними в визуализациях, смотрите, как они реагируют на фильтры.

Делайте ошибки — это лучший способ учиться!

Я вложил в эту статью все свои силы, чтобы сделать ее максимально понятной и вдохновляющей.
Надеюсь, вы почувствовали это. Теперь ваша очередь взять эти знания и превратить их в реальные аналитические суперспособности. Удачи!