В отличие от TopCount()/BottomCount(), которые возвращают набор элементов, функция Rank() присваивает числовой ранг каждому элементу в наборе. Это позволяет вам видеть позицию каждого элемента относительно других, а не только попадает ли он в верхний или нижний список. Rank() обычно используется для создания расчетной меры, которая отображает ранг.
Концепция ранжирования с Rank()Rank() вычисляет ранг элемента в заданном наборе на основе заданного выражения. Если несколько элементов имеют одинаковое значение выражения, Rank() присваивает им одинаковый ранг, а следующий ранг будет пропущен (например, 1, 2, 2, 4).
Синтаксис:
Rank(Member_Expression, Set_Expression [, Numeric_Expression])
● Member_Expression: Член, для которого вычисляется ранг (обычно CurrentMember на оси).
● Set_Expression: Набор, в котором производится ранжирование.
● Numeric_Expression: Необязательное выражение, по которому производится ранжирование. Если не указано, ранг определяется порядком члена в наборе.
Пример 4: Ранжирование продуктов AdventureWorks по продажам за 2007 годДавайте присвоим ранг каждому продукту на основе его продаж.
WITH MEMBER [Measures].[Product Sales Rank] AS
Rank(
[Product].[Product].CurrentMember, -- Текущийпродукт, длякотороговычисляетсяранг
NON EMPTY [Product].[Product].[Product Name].Members, -- Набор, в котором ранжируем
([Measures].[Sales Amount], [Date].[Calendar Year].&[2007]) -- Выражение для ранжирования
)
, FORMAT_STRING = "#,##0"
SELECT
{[Measures].[Sales Amount], [Measures].[Product Sales Rank]} ON COLUMNS,
NON EMPTY [Product].[Product].[Product Name].Members ON ROWS
FROM
[Adventure Works]
WHERE
[Date].[Calendar Year].&[2007]
ORDER BY
[Measures].[Product Sales Rank] ASC
Разбор:
● Мы создаем расчетную меру [Measures].[Product Sales Rank].
● Rank([Product].[Product].CurrentMember, ...): CurrentMember ссылается на каждый продукт по очереди, когда MDX итерирует по оси ROWS.
● NON EMPTY [Product].[Product].[Product Name].Members: Мы ранжируем только те продукты, у которых есть продажи, чтобы избежать ранжирования пустых элементов.
● ORDER BY [Measures].[Product Sales Rank] ASC: Мы явно сортируем результат по рангу, чтобы видеть продукты в порядке их ранжирования.
Обработка связанных рангов (Ties):
Если два или более продукта имеют одинаковую сумму продаж, Rank() присвоит им одинаковый ранг. Например, если два продукта делят 5-е место, они оба получат ранг 5, а следующий продукт получит ранг 7 (ранг 6 будет пропущен). Это стандартное поведение, известное как "плотный ранг" (dense rank) в некоторых SQL-диалектах, но в MDX это просто поведение Rank(). Это важно учитывать при интерпретации отчетов.
Пример 5: Ранжирование подкатегорий внутри каждой категории AdventureWorks
Это более сложный сценарий, где ранг вычисляется в контексте родительского элемента.
WITH MEMBER [Measures].[Subcategory Sales Rank] AS
Rank(
[Product].[Subcategory].CurrentMember,
-- Набор, в котором ранжируем: дочерние элементы текущей категории
NON EMPTY [Product].[Category].CurrentMember.Children,
([Measures].[Sales Amount], [Date].[Calendar Year].&[2007])
)
, FORMAT_STRING = "#,##0"
SELECT
{[Measures].[Sales Amount], [Measures].[Subcategory Sales Rank]} ON COLUMNS,
NON EMPTY
Generate(
[Product].[Category].Members, -- Итерируемпокаждойкатегории
Order(
[Product].[Category].CurrentMember.Children, -- Дочерниеэлементытекущейкатегории
([Measures].[Sales Amount], [Date].[Calendar Year].&[2007]),
BDESC
)
) ON ROWS
FROM
[Adventure Works]
WHERE
[Date].[Calendar Year].&[2007]
Разбор:
● Rank([Product].[Subcategory].CurrentMember, NON EMPTY [Product].[Category].CurrentMember.Children, ...): Здесь Rank вычисляется для каждой подкатегории (CurrentMember), но набор для ранжирования ограничен [Product].[Category].CurrentMember.Children. Это означает, что ранг будет присвоен только среди подкатегорий текущей родительской категории.
● Generate() используется для итерации по каждой категории и отображения ее дочерних подкатегорий, отсортированных по продажам. Это позволяет увидеть ранг каждой подкатегории внутри ее категории.