Комбинируя CrossJoin() и Generate() с другими функциями, такими как Filter(), NonEmpty() и функциями навигации по иерархии, можно решать очень сложные аналитические задачи, которые требуют глубокого понимания взаимодействия контекстов.
Сценарий 1: Продукты AdventureWorks, которые продавались в каждом квартале 2007 года
Это классический пример "всех" условий, который требует итерации и проверки наличия данных во всех подпериодах.
WITH SET [All Quarters 2007] AS
[Date].[Calendar].[Calendar Quarter].Members
WHERE
[Date].[Calendar Year].CurrentMember IS [Date].[Calendar Year].&[2007]
SELECT
[Measures].[Sales Amount] ON COLUMNS,
NON EMPTY
Filter(
[Product].[Product].[Product Name].Members,
Count(
Filter(
[All Quarters 2007],
NOT IsEmpty(([Measures].[Sales Amount], [Product].[Product].CurrentMember, [Date].[Calendar].CurrentMember))
)
) = Count([All Quarters 2007])
) ON ROWS
FROM
[Adventure Works]
Разбор:
● [All Quarters 2007]: Именованный набор всех кварталов 2007 года. Это упрощает ссылку на полный набор периодов.
● Filter([Product].[Product].[Product Name].Members, ...): Мы итерируем по каждому продукту, чтобы проверить условие.
● Внутри Filter, Count(Filter([All Quarters 2007], NOT IsEmpty(...))): Для каждого продукта мы считаем, в скольких кварталах 2007 года у него были непустые продажи. IsEmpty() проверяет, является ли ячейка пустой.
● Count([All Quarters 2007]): Это общее количество кварталов в 2007 году (4).
● Условие ... = Count([All Quarters 2007]) означает, что продукт должен был иметь продажи во всех 4 кварталах. Только такие продукты будут включены в результирующий набор.
Сценарий 2: Клиенты AdventureWorks, которые купили 'Road Bikes' И 'Mountain Bikes'Это пример фильтрации по пересечению наборов, демонстрирующий, как можно комбинировать результаты разных фильтров.
WITH SET [Customers Who Bought Road Bikes] AS
NON EMPTY
Filter(
[Customer].[Customer].[Customer].Members,
([Measures].[Order Quantity], [Product].[Subcategory].&[Road Bikes]) > 0
)
SET [Customers Who Bought Mountain Bikes] AS
NON EMPTY
Filter(
[Customer].[Customer].[Customer].Members,
([Measures].[Order Quantity], [Product].[Subcategory].&[Mountain Bikes]) > 0
)
SELECT
[Measures].[Order Quantity] ON COLUMNS,
NON EMPTY
Intersect(
[Customers Who Bought Road Bikes],
[Customers Who Bought Mountain Bikes]
) ON ROWS
FROM
[Adventure Works]
WHERE
[Date].[Calendar Year].&[2007]
Разбор:
● Мы создаем два именованных набора: [Customers Who Bought Road Bikes] для клиентов, купивших 'Road Bikes', и [Customers Who Bought Mountain Bikes] для клиентов, купивших 'Mountain Bikes'. Использование NON EMPTY внутри этих определений помогает оптимизировать промежуточные наборы.
● Intersect(): Эта функция возвращает набор членов, которые присутствуют в обоих входных наборах. Таким образом, мы получаем список клиентов, которые купили оба типа велосипедов.
Этот сценарий показывает, как можно использовать именованные наборы для построения промежуточных результатов, а затем комбинировать их с помощью функций для работы с наборами (Intersect, Union, Except) для получения окончательной выборки. Это делает запрос более модульным и легко читаемым.
Сценарий 3: Продажи AdventureWorks по регионам для клиентов, совершивших покупки в 'Черную пятницу' 2007 года Предположим, мы хотим проанализировать продажи по регионам, но только для тех клиентов, которые совершили хотя бы одну покупку в 'Черную пятницу' 2007 года (пусть это будет 23 ноября 2007 года).
WITH MEMBER [Date].[Calendar].[Black Friday 2007] AS
[Date].[Calendar].[Date].&[20071123] -- Пример даты Черной пятницы
SET [Black Friday Customers] AS
NON EMPTY
Filter(
[Customer].[Customer].[Customer].Members,
([Measures].[Order Quantity], [Date].[Calendar].[Black Friday 2007]) > 0
)
SELECT
[Measures].[Sales Amount] ON COLUMNS,
NON EMPTY [Geography].[Sales Territory].[Sales Territory Group].Members ON ROWS
FROM
[Adventure Works]
WHERE
([Black Friday Customers], [Date].[Calendar Year].&[2007])
Разбор:
● Мы сначала определяем расчетный член [Black Friday 2007] для конкретной даты.
● Затем создаем именованный набор [Black Friday Customers], который фильтрует всех клиентов, оставляя только тех, у кого количество заказов в этот конкретный день было больше нуля.
● Наконец, мы используем этот набор [Black Friday Customers] в слайсере WHERE вместе с 2007 годом, чтобы получить общие продажи по регионам, но только от клиентов, которые были активны в 'Черную пятницу'.
Этот пример демонстрирует, как можно использовать комбинацию расчетных членов и именованных наборов для создания очень специфических аналитических срезов.