Меня часто спрашивают об основных отличиях DAX и MDX или в целом о различии табличной и многомерной модели.

С точки зрения выражения или языка запросов, одно из наиболее важных различий лежит во внутренней основе обоих подходов.

В кубе, для адресации ячейки в пространстве, у нас есть понятие кортежа. Ось в кортеже устанавливает координаты. Если у нас есть единственный кортеж, то результат — содержание соответствующей ячейки в кубе. Поскольку у атрибутов куба есть элемент All, который служит значением по умолчанию (в большинстве случаев), если атрибут не был включен в кортеж, то мы выполняем агрегацию также, как если бы он там был. Например, следующий кортеж возвращает (агрегированный) объем продаж за 2013 год

(Date.Calendar.[Calendar Year].&[2013], Measures.[Internet Sales Amount])

Другие атрибуты (Product, например) находятся на уровне элементов по умолчанию. Как видите, в этом случае нет необходимости указывать агрегатную функцию (несмотря на то, что в 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] 
)

Такой подход кажется естественным. Используя дочернюю функцию мы создаем набор всех дат для выбранного элемента (например: месяц, квартал, год). Далее мы отфильтровываем этот набор с помощью функции Filter таким образом, чтобы в наборе остались только суббота и воскресенье. Наконец мы агрегируем объем продаж по этому набору.

Фактически этот способ решения очень похож на 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, мы скорее думаем

  • Как отфильтровать базовые таблицы
  • Какую функцию агрегации использовать

То в MDX, в свою очередь, мы скорее думаем

  • На какую ось мне сослаться, чтобы извлечь нужное значение из куба

Комментарии (0)