Incorrect results in TOPCOUNT query for some attributes - mdx

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

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:

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

Account for tied ranks

I'm using the following:
WITH
SET [myset] AS
Order
(
{
[Customer].[Country].[Country].MEMBERS
*
[Customer].[Customer].[Customer].MEMBERS
}
,[Measures].[Internet Sales Amount]
,ASC
)
MEMBER [Measures].[rank] AS
Rank
(
(
[Customer].[Country].CurrentMember
,[Customer].[Customer].CurrentMember
)
,[myset]
)
MEMBER [Measures].[newrank] AS
IIF
(
[myset].Item(
[Measures].[rank] - 1).Item(0).Name
<>
[myset].Item(
[Measures].[rank] - 2).Item(0).Name
,1
,
([myset].Item([Measures].[rank] - 2),[Measures].[newrank]) + 1
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[rank]
,[Measures].[newrank]
} ON 0
,[myset] ON 1
FROM [Adventure Works];
It is the work of Amish Shah: http://blog.sqltechie.com/2010/03/rank-with-partitioning-mdx.html
Currently it does not give tuples that have the same value the same rank e.g. if x has an Internet Sales Amount of 10 and y also has 10, in the above they will not have the same rank.
Can the above be changed so that if they have the same value then they have the same value for [Measures].[rank] - and also the same value for [Measures].[newrank]?
(adding a third argument into the definition of [Measures].[rank] doesn't seem like a possible route to proceed as the Rank function then goes into cel-by-cell calculation mode)
How about using recursive calculated members like so -
WITH
SET [myset] AS
Order
(
{
[Customer].[Country].[Country].MEMBERS
*
[Customer].[Customer].[Customer].MEMBERS
}
,[Measures].[Internet Sales Amount]
,ASC
)
MEMBER [Measures].[myrank] AS
Rank
(
(
[Customer].[Country].CurrentMember
,[Customer].[Customer].CurrentMember
)
,[myset]
)
member prevmembervalue as
(myset.item(myRank - 2), [Measures].[Internet Sales Amount])
member currentmembervalue as
(myset.item(myRank - 1), [Measures].[Internet Sales Amount])
MEMBER greaterthanprev as
iif(currentmembervalue > prevmembervalue, 1, 0)
member rankActual as
iif
(
prevmembervalue = null, 1,
iif(currentmembervalue > prevmembervalue,
(myset.item(myRank - 2), rankActual) + 1,
(myset.item(myRank - 2), rankActual)
)
)
select myset on 1,
{[Measures].[Internet Sales Amount], rankActual, myRank}
on 0
from
[Adventure Works]
The measures greaterthanprev, currentmembervalue and prevmembervalue are actually not needed. Added them here just for some added clarification on the process.

Elegant way to ignore null when applying RANK

This article gives a method for ignoring null when applying RANK : http://www.bidn.com/blogs/CraigLove/ssas/2617/mdx-walkthrough
Is there a more elegant way of doing this than using CASE ?
WITH
MEMBER [Measures].[City Rank]
AS
CASE
WHEN
NOT ISEMPTY
(
(
[Geography].[City].CurrentMember
,[Measures].[Reseller Sales Amount]
)
)
THEN
RANK
(
[Geography].[City].CurrentMember
,[Geography].[City].AllMembers
,[Measures].[Reseller Sales Amount]
)
ELSE
NULL
END
SET [OrderedCity]
AS
ORDER
(
[Geography].[City].AllMembers
,[Measures].[Reseller Sales Amount]
,DESC
)
SELECT
{
[Measures].[City Rank]
,[Measures].[Reseller Sales Amount]
} ON COLUMNS
,NON EMPTY [OrderedCity] ON ROWS
FROM [Adventure Works];
You could apply the NonEmpty function within OrderedCity:
WITH
SET [OrderedCity]
AS
NonEmpty(
ORDER
(
[Geography].[City].AllMembers
,[Measures].[Reseller Sales Amount]
,DESC
)
)
MEMBER [Measures].[City Rank]
AS
RANK
(
[Geography].[City].CurrentMember
,[OrderedCity]
)
SELECT
{
[Measures].[City Rank]
,[Measures].[Reseller Sales Amount]
} ON COLUMNS
,[OrderedCity]
ON ROWS
FROM [Adventure Works];
This way the NON EMPTY is applied on the set on the rows before it it put there, so there is no need to apply it on the rows themselves. Furthermore, re-using the set within the definition of City Rank allows Analysis Services to calculate the sorting only once, and cache the ordered set. Otherwise, the Rank would require the ordering to be re- calculated for each row.