Convert sql rank to mdx rank - ssas

This is my sql code - I want to convert it into an mdx query.
Also those results set use into power bi report.
I am unable to write this sql query into mdx query. Can anybody help me?
Select * From(
Select
dense_RANK()over(partition by t.MonthName order by t.amount desc)rank
,t.*
From(
Select DSP.SalesPointShortName ,dd.MonthName
,SUM(fs.salesAmount)Amount
From FactSales FS
INNER JOIN DimDate dd on fs.DateKey=dd.DateKey
INNER JOIN DimSalesPoint DSP on DSP.SalesPointID=FS.SalesPointID
group by dsp.SalesPointShortName ,dd.MonthName
)as t
)as f where f.rank=1
My expected output is:

Lots of google searching i have the answer from below link
After following this link desire results comes.
https://bipassion.wordpress.com/2013/06/22/mdx-dense-rank/
`
WITH SET [Sorted Models] AS
// For each month get Top 25 records, choosed a Top 25 from business case
Generate (
[Dim Date].[Month Name].[Month Name].Members,
TopCount
( nonempty(
{
[Dim Date].[Month Name].CurrentMember
* [Dim Sales Point].[SalesPoint].[Sales Point Short Name].MEMBERS
}
,[Measures].[Sales Amount]
)
, 1
,[Measures].[Sales Amount]
)
)
//Select
//[Measures].[Sales Amount] on 0,[Sorted Models] on 1
//From [MdCubeTest]
//where [Dim Product Group Item].[Sub Category Name].&[Bag]
MEMBER [Measures].[Rank] AS
// Get the Rank of current member Tuple to Current Month Set
// Do not use Sorted Models set due to dynamic for each set
Rank (
(
[Dim Date].[Month Name].CurrentMember
, [Dim Sales Point].[SalesPoint].CurrentMember
)
, Generate ( [Dim Date].[Month Name].CurrentMember,
TopCount
( nonempty(
{ [Dim Date].[Month Name].CurrentMember
* [Dim Sales Point].[SalesPoint].[Sales Point Short Name]
}
,[Measures].[Sales Amount]
)
, 25
,[Measures].[Sales Amount]
)
)
, [Measures].[Sales Amount]
)
MEMBER [Measures].[Previous Set Index] AS
// Get the Set Index using Rank
(
[Measures].[Rank] - 2
)
MEMBER [Measures].[Dense Rank] AS
// Get the Dense Rank using the Index position value
CASE
WHEN [Measures].[Rank] = 1
THEN 1
ELSE
(
[Sorted Models].Item([Measures].[Previous Set Index]),
[Measures].[Dense Rank]
)
+
Iif
(
(
[Sorted Models].Item([Measures].[Previous Set Index]),
[Measures].[Sales Amount]
)
=
[Measures].[Sales Amount]
,0
,1
)
End
SELECT
{
[Measures].[Sales Amount]
, [Measures].[Rank]
, [Measures].[Dense Rank]
//, [Measures].[Previous Set Index]
} ON rows
,NON EMPTY
{
// FILTER Can be used to get the TOP 3 using DENSE RANK
FILTER (
[Sorted Models]
, [Measures].[Dense Rank] <=1
)
} ON columns
FROM [MdCubeTest]
where [Dim Product Group Item].[Sub Category Name].&[Bag]`

Related

MDX SSAS Rank rownumber function

I have an existing SSRS report out of T-SQL query and I am trying to recreate it using MDX queries on SSAS cube. I am stuck with rewriting Row num and rank logic to MDX.
It is written as:
SELECT ceil((ROW_NUMBER() OVER (PARTITION BY PRODUCT ORDER BY YEARMONTH))/12)
Rank1 in the SQL. Can someone tell me if this can be done using MDX? In the cube, PRODUCT and YEARMONTH are coming from separate dimensions.
Thank you for your help!
There is the Rank() function. For example:
with
Dynamic Set OrderedSet as
Order(
NonEmptyCrossJoin(
[Date].[Year].[Year].Members,
[Product].[Product].[Product].Members,
[Measures].[Invoice Count],
2
),
[Measures].[Invoice Count],
BDESC
)
Member [Measures].[Rank] as
Rank(
([Client].[Client].Currentmember,[Date].[Year].CurrentMember),
OrderedSet
)
select {[Measures].[Invoice Count],[Measures].[Rank]} on 0,
non empty OrderedSet on 1
from [BI Fake]
where ([Date].[Day].&[20160120])
You can read in details about it from my blog post.
You can use Generate to repeat ranks like this:
WITH
SET [SalesRank] AS
Generate
(
[Customer].[Customer Geography].[State-Province]
,Order
(
NonEmpty
(
(
[Customer].[Customer Geography].CurrentMember
,[Product].[Product Categories].[Subcategory]
)
,{[Measures].[Internet Sales Amount]}
)
,[Measures].[Internet Sales Amount]
,BDESC
)
)
MEMBER [Measures].[CategoryRank] AS
Rank
(
(
[Customer].[Customer Geography].CurrentMember
,[Product].[Product Categories].CurrentMember
)
,Exists
(
[SalesRank]
,[Product].[Product Categories].CurrentMember
)
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[CategoryRank]
} ON 0
,[SalesRank] ON 1
FROM [Adventure Works];
It results in this:

DAX - RANK Function

I have a RANK code from WEBI and need to write similar one in DAX or MDX.Both can work. But DAX will be more useful.
=Rank([OrderCount];([Category1];[Category2];[Category3]))
I have tried below code in DAX but it is not exact what i need.
=RANK.EQ(table1[OrderCount];table1[OrderCount])
Can you help me out write similar?
Grouping by Count. This is extra.
I'm not very good at DAX, but MDX way is the following:
with
Dynamic Set OrderedSet as
Order(
NonEmptyCrossJoin(
[Dim Product].[Subcategory Name].[Subcategory Name].Members,
[Dim Product].[Category Name].[Category Name].Members
[Measures].[Order Quantity],
2
),
[Measures].[Order Quantity],
BDESC
)
Member [Measures].[Rank] as
Rank(
([Dim Product].[Subcategory Name].Currentmember,
[Dim Product].[Category Name].Currentmember),
OrderedSet
)
select
{[Measures].[Order Quantity],[Measures].[Rank]} on 0,
non empty OrderedSet on 1
from
[Adventure Works DW2016CTP3]
DenseRank:
with
Dynamic Set OrderedSet as
Order(
NonEmptyCrossJoin(
[Dim Product].[Subcategory Name].[Subcategory Name].Members,
[Dim Product].[Category Name].[Category Name].Members,
[Measures].[Order Quantity],
2
),
[Measures].[Order Quantity],
BDESC
)
Dynamic Set DenseOrderedSet as
Order(
NonEmpty(
OrderedSet,
[Measures].[RankFirstMatch]
),
[Measures].[Order Quantity],
BDESC
)
Member [Measures].[Rank] as
Rank(
([Dim Product].[Subcategory Name].Currentmember,[Dim Product].[Category Name].CurrentMember),
OrderedSet
)
Member [Measures].[RankFirstMatch] as
IIF(
[Measures].[Order Quantity]
=
(
OrderedSet.Item([Measures].[Rank] -2),
[Measures].[Order Quantity]
),
NULL,
[Measures].[Rank]
)
Member [Measures].[RankDenseSet] as
Rank(
([Dim Product].[Subcategory Name].Currentmember,[Dim Product].[Category Name].CurrentMember),
DenseOrderedSet
)
Member [Measures].[DenseRank] as
IIF(
[Measures].[RankDenseSet] = 0,
(OrderedSet.Item([Measures].[Rank] -2),[Measures].[DenseRank]),
[Measures].[RankDenseSet]
)
select {[Measures].[Order Quantity],[Measures].[Rank],[Measures].[RankFirstMatch],[Measures].[RankDenseSet],[Measures].[DenseRank]} on 0,
non empty OrderedSet on 1
from [Adventure Works DW2016CTP3]
Here is the DAX measure for your question:
Rank =
IF (
HASONEVALUE ( YourTableName[ProductName] ),
RANKX (
ALL ( YourTableName ),
CALCULATE ( SUM ( YourTableName[Order Quantity] ) ),
,
,
DENSE
)
)
IF (HASONEVALUE ( YourTableName[ProductName] ).... part will eliminate your Grand Total from showing 1

Ranking of multiple dimensions, restarting for every year

I have a measure, Sales Amount. I want to rank customers within a divison by year for that measure. I need to also display that rank as a measure. The rank needs to start over every year. I am able to do customers by year and customers by division, but I can't seem to figure out how to combine them both so it iterates over both dimensions properly. Below is what I have for the customers by year. I have tried adding another Division set, creating another named set that I GENERATE with the YearsWithCustomers set, and RANK using that new named set. I seem to be super close to figuring this out but I think I am putting something in the wrong place. I got the idea to iterate over a set from one of Chris Webb's blogs, located here.
WITH
SET Years AS
TopPercent
(
[Sales and Forecast Date].[Calendar Year].[Year Number].MEMBERS
,100
,[Measures].[Sales Amount]
)
SET Customers AS
Filter
(
[Customer].[Customer Number].[Customer Number].MEMBERS
,
[Measures].[Sales Amount] > 0
)
SET YearsWithCustomers AS
Generate
(
Years
,Union
(
{[Sales and Forecast Date].[Calendar Year].CurrentMember}
,StrToSet
("
Intersect({},
{order(Customers,([Sales Amount],[Sales and Forecast Date].[Calendar Year].CurrentMember),desc)
as CustomerSet"
+
Cstr(Years.CurrentOrdinal)
+ "})"
)
)
,ALL
)
MEMBER [Measures].[Customer Rank] AS
Rank
(
[Customer].[Customer Number].CurrentMember
,StrToSet
("CustomerSet"
+
Cstr
(
Rank
(
[Sales and Forecast Date].[Calendar Year].CurrentMember
,Years
)
)
)
)
SELECT
{
[Customer Rank]
,[Measures].[Sales Amount]
} ON 0
,Order
(
Filter
(
(
YearsWithCustomers
,Customers
)
,
[Sales Amount] > 0
)
,[Sales Amount]
,desc
) ON 1
FROM [OrdersAndBudgets];
Here is what I currently have. I would expect to see 1, 2, 3, etc for the Rank measure. It should reset for each division for every year.
I like this sort of pattern:
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries] AS a
,{
(
a.CurrentMember
,[Product].[Product].[All]
)
+
//The top x prods
a.CurrentMember
*
TopCount
(
[AllProds]
,5
,[Measures].[Internet Sales Amount]
)
}
)
MEMBER [Product].[Product].[All].[Other Products] AS
Aggregate
(
[Country].CurrentMember * [Product].[Product].[Product].MEMBERS
-
[Top5Prods]
)
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,Hierarchize(
{
[Top5Prods]
,[AllCountries] * [Product].[Product].[All].[Other Products]
}
) ON ROWS
FROM [Adventure Works];
It returns the following:
There is quite an extensive thread here: Top X of Top Y with RestOf member where X and Y are hierarchies from different dimensions

Incorrect results in TOPCOUNT query for some attributes

I am trying to find out which year had the highest reseller sales across each of the State-Province. I am using Adventure Works DW 2008 R2 database.
Here is the query that I have got -
SELECT { [Reseller Sales Amount] } ON COLUMNS,
{
Generate (
[Geography].[Geography].[Country].Members,
TopCount (
Order (
Descendants (
[Geography].[Geography].CurrentMember
, [Geography].[Geography].[State-Province]
)
*[Date].[Calendar].[Calendar Year].Members,
[Reseller Sales Amount],
DESC
),
1
)
)
} ON ROWS
FROM [Adventure Works]
When it comes to France it's displaying (null) as result set. Also why is it not listing all the State-Provinces but only select few of them? Is it also possible to get the Country alongside the results. When I tried another cross-join I get error saying Geography hierarchy already exists.
To get rid of the null you can use BDESC rather than DESC. The extra B means that all natural hierarchy order will be Broken
SELECT { [Reseller Sales Amount] } ON COLUMNS,
{
Generate (
[Geography].[Geography].[Country].Members,
TopCount (
Order (
Descendants (
[Geography].[Geography].CurrentMember
, [Geography].[Geography].[State-Province]
)
*[Date].[Calendar].[Calendar Year].Members,
[Reseller Sales Amount],
BDESC //<<<
),
1
)
)
} ON ROWS
FROM [Adventure Works];
To add in country and avoid the error that you are seeing use the unused attribute hierarchy [Geography].[Country] rather than the user hierarchy [Geography].[Geography] which you already have on the 1 axis:
SELECT
{[Reseller Sales Amount]} ON COLUMNS
,{
Generate
(
[Geography].[Geography].[Country].MEMBERS
,TopCount
(
Order
(
[Geography].[Country].[Country]*
Descendants
(
[Geography].[Geography].CurrentMember
,[Geography].[Geography].[State-Province]
)*
[Date].[Calendar].[Calendar Year].MEMBERS
,[Reseller Sales Amount]
,bDESC
)
,1
)
)
} ON ROWS
FROM [Adventure Works];
Results are the following:
We will explore the universal option realization of TOP-filters on the levels.
TOP-rules can be set for every level.
It is used for detailed of analysis of data (Expand, Drilldown).
Aggregates are formed based on TOP.
Setting the Sort order will do, as long as the data is sorted in the
most Pivot Table.
SELECT
{ [Measures].[Reseller Sales Amount] }
DIMENSION PROPERTIES PARENT_UNIQUE_NAME , HIERARCHY_UNIQUE_NAME , CUSTOM_ROLLUP , UNARY_OPERATOR , KEY0 ON 0
, ORDER
( HIERARCHIZE
( HIERARCHIZE ( [Geography].[Geography].Levels ( 0 ).Members )
)
, ([Measures].[Reseller Sales Amount])
, BDESC
)
DIMENSION PROPERTIES PARENT_UNIQUE_NAME , HIERARCHY_UNIQUE_NAME , CUSTOM_ROLLUP , UNARY_OPERATOR , KEY0 ON 1
FROM
( SELECT
{ Generate
( [Geography].[Geography].Levels ( 3 ).Members
, TopCount
( Filter
( [Geography].[Geography].CurrentMember.Children
, NOT IsEmpty ( [Measures].[Reseller Sales Amount] )
)
, 3
, [Measures].[Reseller Sales Amount]
)
)
} ON COLUMNS
FROM
( SELECT
{ Generate
( [Geography].[Geography].Levels ( 2 ).Members
, TopCount
( Filter
( [Geography].[Geography].CurrentMember.Children
, NOT IsEmpty ( [Measures].[Reseller Sales Amount] )
)
, 3
, [Measures].[Reseller Sales Amount]
)
)
} ON COLUMNS
FROM
( SELECT
{ Generate
( [Geography].[Geography].Levels ( 1 ).Members
, TopCount
( Filter
( [Geography].[Geography].CurrentMember.Children
, NOT IsEmpty ( [Measures].[Reseller Sales Amount] )
)
, 3
, [Measures].[Reseller Sales Amount]
)
)
} ON COLUMNS
FROM
( SELECT
{ Generate
( [Geography].[Geography].Levels ( 0 ).Members
, TopCount
( Filter
( [Geography].[Geography].CurrentMember.Children
, NOT IsEmpty ( [Measures].[Reseller Sales Amount] )
)
, 3
, [Measures].[Reseller Sales Amount]
)
)
} ON COLUMNS
FROM
( SELECT
{ [Geography].[Geography].Levels ( 0 ).Members } ON COLUMNS
FROM [Adventure Works]
)
)
)
)
)
CELL PROPERTIES BACK_COLOR , CELL_ORDINAL , FORE_COLOR , FONT_NAME , FONT_SIZE , FONT_FLAGS , FORMAT_STRING , VALUE , FORMATTED_VALUE , UPDATEABLE , ACTION_TYPE

Equivalent to max group by in mdx

How do I get the sales for the last product of a cross join of each product group and brand? I had a look at the Tail function but I can't get it to work properly.
This is the MDX I have so far:
SELECT {[Measures].[Sales Amount]} ON COLUMNS,
{
[Dim Brands].[Brand Name].[Brand Name].ALLMEMBERS *
[Dim Product Groups].[Product Group Name].[Product Group Name].ALLMEMBERS *
Tail ([Dim Products].[Product Name].[Product Name].ALLMEMBERS)
}
It only returns the last product for the whole cube rather than the last product for each brand and product group.
You can use the GENERATE function to generate the product for every combo or Brand and product group. The EXISTING takes care of the scope.
WITH SET LastProductForEachBrandAndProductGroup AS
GENERATE
(
EXISTING
NonEmpty
(
[Dim Brands].[Brand Name].[Brand Name].ALLMEMBERS, [Dim Product Groups].[Product Group Name].[Product Group Name].ALLMEMBERS
)
,
Tail (
[Dim Products].[Product Name].[Product Name].ALLMEMBERS
)
)
SELECT {[Measures].[Sales Amount]} ON COLUMNS,
NonEmpty({
[Dim Brands].[Brand Name].[Brand Name].ALLMEMBERS *
[Dim Product Groups].[Product Group Name].[Product Group Name].ALLMEMBERS *
LastProductForEachBrandAndProductGroup
}) ON ROWS
FROM YourCube
If by last, you imply the last member in any sorted(by some measure) list, the above would need some more work. Let me know how it works out for you.
Separating out the sets should speed this script up. Like the following:
WITH
SET [allBrands] AS
[Dim Brands].[Brand Name].[Brand Name].ALLMEMBERS
SET [allGroups] AS
[Dim Product Groups].[Product Group Name].[Product Group Name].ALLMEMBERS
SET [A] AS
Generate
(
{[allBrands] * [allGroups]} AS s
,
s.Current
*
Tail
(
NonEmpty
(
[Dim Products].[Product Name].[Product Name].ALLMEMBERS
,[Measures].[Sales Amount]
)
,1
)
)
SELECT
NON EMPTY
{[Measures].[Sales Amount]} ON 0
,NON EMPTY
[A] ON 1
FROM [YourCube];
Against Microsoft's AdvWrks a similar, and maybe more useful, variant of the above would be to use TopCount rather than the slightly artitrary Tail:
WITH
SET [allYears] AS
[Date].[Calendar].[Calendar Year].MEMBERS
SET [allCountries] AS
[Customer].[Customer Geography].[Country].MEMBERS
SET [A] AS
Generate
(
{[allYears] * [allCountries]} AS s
,
s.Current
*
TopCount
(
[Product].[Product Categories].[Product].ALLMEMBERS
,2
,[Measures].[Internet Sales Amount]
)
)
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,[A] ON 1
FROM [Adventure Works];
This results in the following: