Синтаксис языка mdx
Запрос на языке MDX представляет собой набор команд, который выглядит следующим образом:
SELECT <описание осей куба>
FROM <название куба>
WHERE <описание срезов куба>
Полный SELECT-запрос должен содержать:
В одном запросе можно указать до 128 осей,
Список членов измерения, которые должны быть включены для каждой
оси,
Имя куба, к которому производится запрос,
Список членов среза.
Модели данных mdx: кортежи и множества Кортежи
Язык MDX оперирует не только с размерностями (Dimensions), но и с кортежами. Кортеж - это комбинация членов из одной или более размерностей, удобная для манипуляций в MDX. Например, простой кортеж, состоящий из членов одной размерности: [YQMD].[1997].
Для составления кортежа, содержащего члены более чем одной размерности, необходимо все члены поместить в круглые скобки: ([Product]. [Beverages], [Customer]. [Brazil]).
Построенные кортежи можно вызывать с помощью запросов, например результатом выполнения запроса: SELECT
{ ([YQMD].[A11 YQMD].[1997], [Measures].[Discounted Total]), ([YQMD].[A11 YQMD].[1997], [Measures].[Line Item Discount]), ([YQMD].[A11 YQMD].[1996], [Measures].[Discounted Total]), ([YQMD].[A11 YQMD].[1996], [Measures].[Line Item Discount])
}
ON COLUMNS,
{[Product].[All Product].[Beverages].[Chai], [ProductUAll Product].[Beverages].[Ipoh Coffee]} ON ROWS
FROM Sales
Будет:
Рис. 1. Операции с использованием кортежей
Примечание: Нельзя использовать пустые кортежи () или использовать в одном кортеже 2 члена одного измерения, например временные ([YQMD].[1996], [YQMD].[1997]).
Множества
Множество - это запрос набора кортежей. Множество может включать в себя более одного кортежа, один кортеж или быть пустым. Кроме того, множество может содержать несколько одинаковых кортежей. В зависимости от контекста, в котором
используется множество, оно означает либо множество кортежей, либо значения в ячейках, определяемые кортежами.
Синтаксически, множество можно определить через набор кортежей, перечислив их в фигурных скобках {}. В качестве примера рассмотрим запрос, по колонкам которого два простых множества, а по рядам — одно:
SELECT
{ ([YQMD].[A11 YQMD].[1997].[1]), ([YQMD].[A11 YQMD].[1997])
}
ON COLUMNS,
{[Product].[All Product].[Meat/Poultry], [Product].[All Product].[Seafood]} ON ROWS
FROM Sales
Результатом выполнения запроса становятся данные по 1 кварталу 1997 года и всему 1997 году о продажах мясных и морских продуктов.
|
1 Квартал |
1997 |
Meat/Poultry |
24 152,30p, |
87 648,12р. |
Seafood |
8 092,60р. |
69 780,30р. |
Рис. 2. Множества в запросе.
Примечание: Отличия кортежей от множеств по синтаксису:
Множество, содержащее кортеж «{([YQMD].[All YQMD].[1997])}»;
Кортеж «([YQMD].[All YQMD].[1997])».
Примечание: Множество может быть пустым, например {}.
Изучив модели данных в MDX, можем приступить к более подробному рассмотрению применения MDX в приложении Microsoft SQL Server 2000 Analysis Services.
MDX Sample Application
В Microsoft SQL Server 2000 Analysis Services выберем утилиту MDX Sample Application. При запуске на экране появляется панель Connect, в которой необходимо указать имя сервера (имя компьютера, на котором установлен Microsoft SQL Server 2000 Analysis Services) и тип провайдера для связи с сервером - MSOLAP.
Рис. 3. Панель Connect
После выбора параметров связи можно нажать ОК. Открывшееся приложение содержит панели:
1. выбор базы данных MS SQL Server 2000 (в нашем примере это Northwind_s),
2. выбор куба, созданного в MS SQL Server 2000 Analysis Services, на основе данных таблицы факта БД Northwind_s (Sales).
Рис. 4. Панели инструментов MDX Sample Application
Панель, обозначенная под номером 3 на рис.2 отображает текст mdx-запроса, выбранного на панели Queries справа от панели выбора базы данных, или создаваемого пользователем. По умолчанию, в списке запросов находятся запросы из файла MDXQuery.mdx. Для загрузки другого файла или сохранения текущего используются команды меню File.
Примечание. При построении_МБХ-запроса названия осей можно вводить как
непосредственно с клавиатуры, так и перетаскивать мышью из панели «Измерения
куба» (4 на рис.2). Выполнение запроса осуществляется с помощью команды Run в
11 меню Query, нажатием клавиши F5 или нажатием стрелки «вправо» на панели инструментов.
Результат выполнения запроса отображается в нижней части экрана или, если выбрана
опция View | Results, во весь экран.
Ниже рассмотривается язык MDX применительно к Microsoft SQL Server 2000 Analysis Services.
Все примеры будут выполнены в демонстрационной базе FoodMart 2000, входящей в состав Analysis Services (в ней представлены данные о продажах за 1997 год, все продажи пришлись на территорию США). Будут рассмотрены только MDX-запросы; MDX-выражения будут оставлены вне рамок этой работы.
Простейшие MDX-запросы
Пример 1. Простейший запрос
SELECT FROM Sales
В этом примере мы получили общее количество проданных единиц (Unit Sales) для всего куба. Поскольку в запросе мы не указали имена членов измерений, были выбраны члены по умолчанию для каждого измерения.
Пример 2. Указание в запросе столбцов
SELECT
{[Measures].[Unit Sales]} ON COLUMNS
FROM Sales
Результат аналогичен результату примера
1
Пример З. Указание в запросе строк
SELECT
{[Measures].[Unit Sales]} ON COLUMNS,
{[Time].[1997]} ON ROWS
FROM Sales
Результат аналогичен вышеприведенному.
Пример 4. Указание фильтра в запросе
Определим общее количество проданной продукции за 1997 год только в магазинах на территории США.
SELECT
{[Measures].[Unit Sales]} ON COLUMNS,
{[Time].[1997]} ON ROWS
FROM Sales
WHERE ([Store].[All Stores].[USA])
Примечание. Результаты всех 4 примеров совпали, т.к. в базе находятся результаты только за 1997 и все продажи пришлись на территорию США.
Использование квадратных скобок
Имя необходимо заключать в квадратные скобки, если оно:
Содержит пробел или другой специальный символ - [Gross Profit].
Совпадает с ключевым словом - [SELECT].
Начинается с цифры - [093Setup].
В общем же случае рекомендуется использовать полные имена, заключенные в квадратные скобки - [Store].[All Stores].[Canada].[ВС].[Vancouver].[Store 19]
Использование запятой для разделения наборов элементов
Пример 5. Использование запятой
Определим общее количество проданной продукции, общие затраты и общая выручка за 1997 год в магазинах на территории США.
SELECT
{[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS,
{[Time].[1997]} ON ROWS
FROM Sales
WHERE ([Store].[All Stores].[USA])
Использование двоеточия для определения диапазона
Пример 6. Использование двоеточия
Напишем запрос для нахождения общего количества проданных единиц с января по август 1997 года
SELECT
{[Measures].[Unit Sales]} ON COLUMNS,
{[Time].[1997].[Ql].[l]:[Time].[1997].[Q3].[8]} ON ROWS
FROM Sales
Использование фигурных скобок для определения набора элементов (sets)
В MDX { } используются для обозначения набора элементов (в том числе именованного). Один набор может быть вложен в другой.
Пример 7. Использование вложенных наборов
SELECT
{[Measures].[Unit Sales]} ON COLUMNS,
{{[Store].[USA].[CA], [Store].[USA].[OR], [Store].[WA]}, [Store].[Canada]} ON ROWS
FROM Sales
Выдается результат по общему количеству продаж в 3 отдельных штатах США и полностью по Канаде.
Использование операторов Children и Members
Пример 8. Использование оператора Children
SELECT
{[Store Type].[All Store Type].Children} ON COLUMNS,
{[Time].[1997].Children} ON ROWS
FROM Sales
WHERE ([Measures].[Store Sales])
Выводится сумма продаж по кварталам 1997 года и по типам магазинов.
Пример 9. Использование оператора Members
SELECT
{[Store Type].Members} ON COLUMNS,
{[Time].Members} ON ROWS
FROM Sales
WHERE ([Measures].[Store Sales])
Выводится сумма продаж по всем значениям измерения Time и Store Type (продажи по всем типам магазинов, а также общий объем продаж и по всем месяцам, кварталам, годам)
Пример 10. Объем продаж в штатах СА и WA в 1 и 2 кварталах 1997 года
SELECT
{[Store].[All Stores].[USA].[CA],[Store].[All Stores].[USA].[WA] } ON COLUMNS,
{[Time].[1997].[ql], [Time].[1997].[q2]} ON ROWS
FROM Sales
Пример 11. Объем продаж морепродуктов, мяса и яиц в штатах С А и WA за все время
SELECT
{[Store].[All Stores].[USA].[CA],[Store].[All Stores].[USA].[WA] } ON COLUMNS, {[Product].[All Products].[Food].[Seafood], [Product].[All Products].[Food].[Meat], [Product].[All Products].[Food].[Eggs] } ON ROWS FROM Sales
Пример 12. Количество сделок и средняя сумма сделки по продуктовой семье за все время
SELECT
{[Measures].[Sales Count], [Measures].[Sales Average] } ON COLUMNS,
{[Product].[Product Family].Members} ON ROWS
FROM Sales
Пример 13. Количество сделок и средняя сумма сделки по продуктовой семье за все время с покупателями-женщинами
SELECT
{[Measures].[Sales Count], [Measures].[Sales Average] } ON COLUMNS,
{[Product].[Product Family].Members} ON ROWS
FROM Sales
WHERE ([Gender].[All Gender].[F])
Пример 14. Количество сделок и средняя сумма сделки по продуктовой семье за все время с покупателями - незамужними женщинами
SELECT
{[Measures].[Sales Count], [Measures].[Sales Average] } ON COLUMNS,
{[Product].[Product Family].Members} ON ROWS
FROM Sales
WHERE ([Gender].[All Gender].[F], [Marital Status].[All Marital Status].[S])
Пример 15. Зависимость количества покупок по продуктовой семье в супермаркетах штата С А от замужества среди женщин в 1 квартале 1997
SELECT
{[Marital Status].Children} ON COLUMNS,
{[Product].[Product Family].Members} ON ROWS
FROM Sales
WHERE ([Measures].[Sales Count], [Gender].[All Gender].[F] ,[Store].[All Stores].[USA].[CA],
[Store Type].[All Store Type].[Supermarket], [Time].[1997].[Ql] )
Таких относительно простых запросов можно написать очень много. Но даже при такой простоте можно получить довольно интересные, а главное полезные для принятия управленческих решений срезы данных.
Использование функции CrossJoin() и оператора *
Функция CrossJoin() используется для пересечения 2 наборов данных. Соответственно, можно делать запросы к нескольким измерениям и размещать их в одной оси.
Пример 16. Использование функции CrossJoin()
SELECT
CROSSJOIN(
{[Customers].[All Customers].[USA]. [CA].[Altadena], [Customers].[All
Customers]. [USA]. [OR]. [Albany]},
{[Product].[Product Family].Members}) on columns,
{[Time].[Year].[1997].Children} on rows
FROM
Sales
WHERE
([Measures].[Store Sales])
Выдается сумма продаж жителям 2 городов (Altadena и Albany) по продуктовой семье с разбивкой по кварталам 1997 года.
Пример 17. Данные по количеству покупок в 1 и 2 кварталах 1997 года по уровню дохода, по штату, по продуктовой семье
SELECT
CROSSJOIN (
{[Time].[1997].[Ql],[Time].[1997].[Q2]},
{[Yearly Income].[Yearly Income].Members}
) on columns,
CROSSJOIN
({[Store].[Store State].members}, {[Product].[Product Family].members})
FROM Sales
WHERE ([Measures].[Sales Count])
Функция CrossJoin() может работать только с 2 измерениями. Но это ограничение можно обойти, используя вложенные функции CrossJoin().
Пример 18. Использование вложенных CrossJoin()
SELECT
CrossJoin(
CrossJoin( {[Customers].[All Customers].[USA].[CA].[Altadena],
[Customers].[All Customers].[USA].[OR].[Albany] },
{ [Product].[Product Family].Members }),
{ [Store].[Store State].[CA], [Store].[Store State].[OR]}) on columns,
{[Time].[Year].[1997].Children} on rows
FROM
Sales
WHERE
([Measures].[Store Sales])
Сумма продаж по кварталам для региона СА и OR жителям городов Altadena и Albany с разбивкой по продуктовой семье.
Оператор * является альтернативой функции CrossJoin() (он также допускает вложения)
Пример 19. Использование *
Аналог примера 17 с использованием *.
SELECT
{{[Time].[1997].[Ql], [Time].[1997].[Q2]} *
{[Yearly Income].[Yearly IncomeJ.Members}}
on columns,
{{[Store].[Store State].members} * {[Product].[Product Family].members}} on rows
FROM Sales
WHERE ([Measures].[Sales Count])
Использование функций Filter(), Order(), TopCount()
Пример 20. Использование Filter()
SELECT
{[Measures].[Sales Count]} on columns,
FILTER({[Product].[Product Name].Members}, ([Measures].[Sales Count], [Time].[Year].[1997]) >75 ) on rows
FROM Sales
i
Отображаются только продукты, по которым за 1997 год было более 75 сделок.
Пример 21. Не показывать пустые ячейки
Отображаются только те семейства продуктов, по которым за 1 квартал 1997 года было не более 888 сделок с гражданами, чей доход находится в промежутке 10-30.
SELECT NON EMPTY {{[Time].[1997].[Ql], [Time].[1997].[Q2]} * {[Yearly Income].[Yearly Income].Members}} on columns,
NON EMPTY FILTER ({{[Store].[Store State].members} * {[Product].[Product Family].members}}, ([Measures].[Sales Count],[Time].[1997].[Ql], [Yearly Income].[All Yearly Income].[$10K - $30K]) <=888 ) on rows
FROM Sales
WHERE ([Measures].[Sales Count])
Пример 22. Использование сортировки Order().
SELECT
{[Measures].[Sales Count]} on columns,
ORDER(
{[Product].[Product Name].Members }, ([Measures].[Sales Count]), BASC ) on rows
FROM Sales
Отображаются продукты в порядке возрастания сделок в 1997.
Пример 23. Совместное использование Order() и Filter().
SELECT
{[Measures].[Sales Count]} on columns,
ORDER(
FILTER(
{[Product].[Product Name].Members}, ([Measures].[Sales Count], [Time].[Year].[1997]) >75 ),
([Measures].[Sales Count], [Time].[Year].[1997]), BDESC) on rows
FROM Sales
Отображаются в порядке убывания продукты, по которым за 1997 год было более 75 сделок.
Пример 24. Использование TopCount()
SELECT
{[Measures].[Sales Count]} on columns,
TOPCOUNT([Product].[Product Name].Members, 5, [Measures].[Sales Count])
on rows
FROM Sales
Отображается пятерка продуктов, по которым было большинство сделок
Пример 25. Совместное использование NonEmpty и TopCount
Определим самый продаваемый товар в каждом штате.
SELECT
{[Measures].[Sales Count]} on columns,
NONEMPTY {{[Store].[Store State].members} * TOPCOUNT({[Product].[Product Name].members},1, [Measures].[Sales Count])} on rows FROM Sales
Использование агрегатных функций
Пример 26. Использование вычислений
Просмотр прибыльности по кварталам 1997
WITH
MEMBER [Measures].[Profitability] AS
'100*[Measures].[Store Sales Net]/[Measures].[Store Sales]'
SELECT
{[Measures].[Store Sales Net], [Measures].[Store Sales], [Measures].[Profitability] } on columns,
{[Time].[ 1997] .Children} on rows
From Sales
Пример 27. Использование функции AVG
Определим среднюю стоимость продаж по кварталам.
WITH
MEMBER [Measures].[TestAVG] AS
AVG(Product.[Product Name].members,[Measures].[Store Sales])'
SELECT
{ [Measures].[Store Sales], [Measures].[TestAVG] } on columns,
{[Time].[1997].Children} on rows
From Sales
Пример 28. Вычисление тренда
WITH
Member Measures.X AS
'Rank(Time, [Time]. [Month] .Members)'
Member Measures.Trend AS 'LinRegPoint(X, [Time].[Month].Members,[Store Sales], x)'
SELECT
{[Store Sales], X, Trend} ON COLUMNS,
[Time].[Month].Members ON ROWS
FROM SALES
Пример 29. Функция проверки условия
WITH MEMBER [Measures].[Diff] AS
'IIF (([Store Cost] > [Store Sales]),([Measures].[Store Cost]-[Measures].[Store Sales Net]),
([Measures].[Store Sales Net]-[Measures].[Store Cost]))'
SELECT
{[Measures].[Store Sales Net],[Measures].[Store Cost], [Measures].[Diff]} on columns,
{[Gender]. [Gender] .members } on rows
from Sales
Функции форматирования
Пример 30. Вычисление процента
Вычислим процент с 2 знаками после запятой.
WITH member [Measures].[Store Profit Rate] as '([Measures].[Store Sales]-[Measures].[Store Cost])/ [Measures].[Store Cost]', format = '#.00%'
SELECT
{[Measures].[Store Cost],[Measures].[Store Sales], [Measures].[Store Profit Rate]} on columns, Order( [Product]. [Product Department] .members, [Measures].[Store Profit Rate], BDESC) on rows
FROM Sales
