Меня часто спрашивают об основных различиях между DAX и MDX или вообще о разнице между табличной и многомерной моделью.
Что касается языка выражений или запросов, одно из наиболее важных различий заключается во внутренней основе обоих подходов.
В кубе для обращения к ячейке в пространстве используется концепция кортежа.
Ось в кортеже задает координаты.
Если у нас есть один кортеж, то результатом будет содержимое соответствующей ячейки куба.
Поскольку атрибуты куба имеют элемент All, который служит значением по умолчанию (в большинстве случаев), если атрибут не был включен в кортеж, мы выполняем агрегирование, как если бы он там был.
Например, следующий кортеж возвращает (агрегированные) продажи за 2013 год.
Другие атрибуты (например, «Продукт») по умолчанию находятся на уровне элемента.(Date.Calendar.[Calendar Year].
&[2013], Measures.[Internet Sales Amount])
Как видите, в этом случае нет необходимости указывать агрегатную функцию (хотя в MDX есть функции для агрегирования значений по наборам), поскольку куб «знает», как агрегировать продажи.
Следующий эскиз иллюстрирует этот способ адресации значения в кубе:
Для табличной модели фильтры в сводной таблице работают так же, как обычная фильтрация в базовых таблицах.
Даже если вы выберете одно значение, в фильтр таблицы можно включить несколько элементов.
Например, если вы примените фильтр для 2013 года, базовая таблица дат будет отфильтрована по всем 365 дням этого года.
Результатом отбора будут все пересечения других таблиц с отфильтрованным показателем.
Здесь нам нужна агрегатная функция для вычисления результата, поскольку эта операция потенциально вернет много строк данных.
Это показано на следующей иллюстрации:
Если вы больше знакомы с SQL, чем с MDX, то концепция фильтрации и агрегации в DAX будет более понятной.
В SQL, как и в DAX, мы обычно ограничиваем количество строк таблицы (используя предложение Where в SQL или функцию FILTER в DAX).
Затем мы выполняем группировку (используя GROUP BY в SQL или функцию SUMMARIZE в DAX) и, наконец, вычисляем агрегаты, используя соответствующую функцию агрегирования (например, SUM).
Однако многие проблемы, требующие таких операций в SQL или DAX, можно решить в MDX только путем обращения к ячейкам.
Позвольте мне привести пример, который я часто использую во время лекций по MDX: вы хотите создать расчетный показатель, показывающий продажи в выходные дни.
Если вы заядлый фанат SQL, решение MDX может выглядеть примерно так: Aggregate(
filter(
descendants(
[Date].
[Calendar].
currentmember, [Date].
[Calendar].
[Date] ) , [Date].
[Day of Week].
currentmember IS [Date].
[Day of Week].
[Sunday] or [Date].
[Day of Week].
currentmember IS [Date].
[Day of Week].
[Saturday] ) ,[Measures].
[Internet Sales Amount]
)
Такой подход кажется естественным.
Используя дочернюю функцию, мы создаем набор всех дат для выбранного элемента (например: месяц, квартал, год).
Далее мы фильтруем этот набор с помощью функции «Фильтр», чтобы в наборе оставались только суббота и воскресенье.
Наконец, мы агрегируем объем продаж по этому набору.
Фактически это решение очень похоже на SQL или DAX. Например, в DAX мы бы выполнили это вычисление практически таким же образом: evaluate(
summarize(
filter(
‚Internet Sales‘
, related(‚Date'[Calendar Year])=2007
)
, ‚Date'[Month]
, "Umsatz"
, Sum(‚Internet Sales'[Sales Amount])
, "UmsatzWE"
, Calculate(
Sum(‚Internet Sales'[Sales Amount])
, Or(
‚Date'[Day Name Of Week]="Sunday"
, ‚Date'[Day Name Of Week]="Saturday"
)
)
)
)
Однако, несмотря на то, что этот DAX-код очень похож на MDX-код, который мы рассмотрели чуть выше, представленная версия MDX по-прежнему остается едва ли не самым сложным из возможных решений.
Поскольку «день недели» — это атрибут куба, мы можем просто сослаться на продажи в выходные дни, но используя кортеж (ну, сумму двух кортежей): ([Measures].
[Internet Sales Amount], [Date].
[Day Name].
[Sunday]) + ([Measures].
[Internet Sales Amount], [Date].
[Day Name].
[Saturday])
Поэтому при написании запроса DAX мы скорее думаем
- Как фильтровать базовые таблицы
- Какую функцию агрегирования использовать
- К какой оси мне следует обратиться, чтобы извлечь желаемое значение из куба?