DAX - RANK Function - mdx

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

Related

Convert sql rank to mdx rank

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]`

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:

How to use avg function in mdx?

I have my mdx query:
SELECT
NON EMPTY
{[Measures].[Amount]} ON COLUMNS
,NON EMPTY
{[Dim Date].[Day Of Week].[Day Of Week].MEMBERS} ON ROWS
FROM
(
SELECT
[Dim Date].[Date Int].&[20140730] : [Dim Date].[Date Int].&[20150730] ON COLUMNS
FROM [Cube]
WHERE
[Dim Client].[Common Client UID].&[{some id}]
);
so i have my a weekday dim, which contain members as numbers from 1-7. Query find returns amount for each weekday, which is summed up, but i want to find out an average, so somehow i need to find out how many items was summed to give me [Measures].[Amount] result. I have tryed with separate member function which didnt worked.
WITH MEMBER [Measures].[Avg] AS
Avg(
( [Dim Date].[Day Of Week].CURRENTMEMBER, [Measures].[Amount] )
)
Avg return exectly the same value. How do i do such a request in mdx?
This will give you an average over 1 member:
WITH MEMBER [Measures].[Avg] AS
Avg(
( [Dim Date].[Day Of Week].CURRENTMEMBER, [Measures].[Amount] )
)
That is because CURRENTMEMBER is returning 1 member.
If you want an average over several members than you need to supply a set as the first argument for the Avg function. Here is an example:
WITH MEMBER [Measures].[Daily Avg] AS
Avg(
Descedants(
[Date].[Date - Calendar Month].CURRENTMEMBER
,[Date].[Date - Calendar Month].[Calendar Day]
,[Measures].[Amount]
)
Although I suspect something like the follwoing should work in your context:
WITH
MEMBER [Measures].[Avg] AS
Avg
(
(EXISTING
[Dim Date].[Date Int].MEMBERS)
,[Measures].[Amount]
)
SELECT
NON EMPTY
{
[Measures].[Amount]
,[Measures].[Avg]
} ON COLUMNS
,NON EMPTY
{[Dim Date].[Day Of Week].[Day Of Week].MEMBERS} ON ROWS
FROM
(
SELECT
[Dim Date].[Date Int].&[20140730] : [Dim Date].[Date Int].&[20150730] ON COLUMNS
FROM [Cube]
WHERE
[Dim Client].[Common Client UID].&[{some id}]
);

MDX query to pivot table based on condition

I'm trying to write MDX query for pivot table.
Similar query in RDBMS is like this:
SELECT stats_Date
,ISNULL(SUM(clicks), 0) AS clicks
,ISNULL(SUM(CASE WHEN ad_type IN (1,3) THEN clicks END), 0) AS keyword_clicks
,ISNULL(SUM(CASE WHEN ad_type IN (2,3) THEN clicks END), 0) AS direct_clicks
FROM STATS_TABLE (NOLOCK)
WHERE stats_Date BETWEEN '2015-06-01' AND '2015-06-30'
GROUP BY stats_Date
I've two dimensions [DIM TIME] & [DIM AD TYPE]
I've tried below MDX query for this:
WITH
MEMBER [Measures].[Clicks Keyword] AS
IIF
(
[DIM AD TYPE].[Ad Type].CurrentMember IS [DIM AD TYPE].[Ad Type].&[1]
,[Measures].[clicks]
,0
)
SELECT {
[Measures].[Clicks]
,[Measures].[Clicks Keyword]
} ON COLUMNS
,{
[DIM TIME].[CalendarHierarchy].[Date]*[DIM AD TYPE].[Ad Type].[Ad Type]
} ON ROWS
FROM [CM_STATS_CUBE]
WHERE ([DIM TIME].[Month].&[201506]:[DIM TIME].[Month].&[201506]})
Sample output of this MDX query looks like this:
Clicks Clicks Keyword
20150501 Invalid (null) 0
20150501 unknown 200 0
20150501 Keyword 500 0
20150501 Ads 300 300
20150502 Invalid (null) 0
20150502 unknown 400 0
20150502 Keyword 600 0
20150502 Ads 500 500
but I want to only group by stats_date and the expected output is:
Clicks Clicks Keyword
20150501 1000 300
20150502 1500 500
Similar example for testing in [Adventure Works] cube database:
WITH
MEMBER [Measures].[Internet Sales Amount US] AS
IIF( [Customer].[Customer Geography].CurrentMember IS [Customer].[Customer Geography].[Country].&[United States]
,[Measures].[Internet Sales Amount]
,NULL
)
SELECT {
[Measures].[Internet Sales Amount]
,[Measures].[Internet Sales Amount US]
} ON 0
,NON EMPTY{[Date].[Calendar].[Date]} ON 1
FROM [Adventure Works]
WHERE {[Date].[Date].&[20050701]:[Date].[Date].&[20050702]}
You don't need to bother with the cross-join [DIM TIME].[CalendarHierarchy].[Date]*[DIM AD TYPE].[Ad Type].[Ad Type]
WITH
MEMBER [Measures].[Clicks Keyword] AS
IIF
(
[DIM AD TYPE].[Ad Type].CurrentMember IS [DIM AD TYPE].[Ad Type].&[1]
,[Measures].[clicks]
,0
)
SELECT
{
[Measures].[Clicks]
,[Measures].[Clicks Keyword]
} ON COLUMNS
,{[DIM TIME].[CalendarHierarchy].[Date]} ON ROWS
FROM [CM_STATS_CUBE]
WHERE
[DIM TIME].[Month].&[201506] : [DIM TIME].[Month].&[201506];
Also I would suggest using null rather than 0 in your IIF function - this should tidy up the result and speed things up:
WITH
MEMBER [Measures].[Clicks Keyword] AS
IIF
(
[DIM AD TYPE].[Ad Type].CurrentMember IS [DIM AD TYPE].[Ad Type].&[1]
,[Measures].[clicks]
,null //<<<<<<<<<<<<<<<<< better to use null rather than 0
)
SELECT
{
[Measures].[Clicks]
,[Measures].[Clicks Keyword]
} ON COLUMNS
, NON EMPTY //<<<<<<<<<<<<<<<<< now if Clicks and Clicks Keyword are both null the respective row will be excluded
{[DIM TIME].[CalendarHierarchy].[Date]} ON ROWS
FROM [CM_STATS_CUBE]
WHERE
[DIM TIME].[Month].&[201506] : [DIM TIME].[Month].&[201506];
Edit
I'd not read your script in enough detail - apologies. You can just just aggregate a set of two tuples:
WITH
MEMBER [Measures].[Clicks Keyword] AS
Sum
(
{
([DIM AD TYPE].[Ad Type].&[1],[Measures].[clicks])
,([DIM AD TYPE].[Ad Type].&[3],[Measures].[clicks])
}
)
SELECT
{
[Measures].[Clicks]
,[Measures].[Clicks Keyword]
} ON COLUMNS
, NON EMPTY //<<<<<<<<<<<<<<<<< now if Clicks and Clicks Keyword are both null the respective row will be excluded
{[DIM TIME].[CalendarHierarchy].[Date]} ON ROWS
FROM [CM_STATS_CUBE]
WHERE
[DIM TIME].[Month].&[201506] : [DIM TIME].[Month].&[201506];
The AdvWrks example you posted would just be a single tuple:
WITH
MEMBER [Measures].[Internet Sales Amount US] AS
(
[Customer].[Customer Geography].[Country].&[United States]
,[Measures].[Internet Sales Amount]
)
SELECT {
[Measures].[Internet Sales Amount]
,[Measures].[Internet Sales Amount US]
} ON 0
,NON EMPTY{[Date].[Calendar].[Date]} ON 1
FROM [Adventure Works]
WHERE {[Date].[Date].&[20050701]:[Date].[Date].&[20050702]}
If you wanted to add in Canada then there seem to be three viable alternatives:
1.
WITH
MEMBER [Measures].[Internet Sales Amount US & Canada] AS
(
[Customer].[Customer Geography].[Country].&[United States]
,[Measures].[Internet Sales Amount]
)
+
(
[Customer].[Customer Geography].[Country].&[Canada]
,[Measures].[Internet Sales Amount]
)
2.
WITH
MEMBER [Measures].[Internet Sales Amount US & Canada] AS
Aggregate
(
{
[Customer].[Customer Geography].[Country].&[United States]
,[Customer].[Customer Geography].[Country].&[Canada]
}
,[Measures].[Internet Sales Amount]
)
3.
(Switch to Sum)
WITH
MEMBER [Measures].[Internet Sales Amount US & Canada] AS
Sum
(
{
(
[Customer].[Customer Geography].[Country].&[Canada]
,[Measures].[Internet Sales Amount]
)
,(
[Customer].[Customer Geography].[Country].&[United States]
,[Measures].[Internet Sales Amount]
)
}
)
Try this:
WITH
MEMBER [Measures].[Clicks Keyword] AS
AGGREGATE({[DIM AD TYPE].[Ad Type].&[1], [DIM AD TYPE].[Ad Type].&[3]}, [Measures].[Clicks])
SELECT NON EMPTY
{
[Measures].[Clicks]
,[Measures].[Clicks Keyword]
} ON COLUMNS
, NON EMPTY
{[DIM TIME].[CalendarHierarchy].[Date]} ON ROWS
FROM [CM_STATS_CUBE]
WHERE
([DIM TIME].[Month].&[201506] : [DIM TIME].[Month].&[201506]);

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: