I'm trying to create a calculated measure in an MDX query that gets the rank for a dimension ordered by a measure. The problem is that for each row all I get is 1 or, the count of the dimension if I change the sort order.
Here is my measure
MEMBER [Measures].[Approved wk to wk Rank] AS RANK (
[FRR Group Matrix].[Group Name].CurrentMember,
ORDER(
[FRR Group Matrix].[Group Name].[Group Name].ALLMEMBERS, [Measures].[Approved wk to wk %], BDESC
),
[Measures].[Approved wk to wk %]
)
My measures are in my columns, and my dimensions in rows. Here is where I define my rows, and where I believe I have the problem:
{ ([FRR Group Matrix].[Group Name].[Group Name].ALLMEMBERS
* [FRR Group Matrix].[FRRCode].[FRRCode].ALLMEMBERS ) } ON ROWS
If I change to the following I will get a good rank, but I still want to keep both columns
{ [FRR Group Matrix].[Group Name].[Group Name].ALLMEMBERS } ON ROWS
So how can I get my rank to work with both tuples?
Put the whole tuple in the RANK and ORDER. NONEMPTY may not be necessary for your specific problem, but it will exclude blanks from your ranking, and probably speed up the execution time.
SET [X] AS
ORDER(
NONEMPTY(
[FRR Group Matrix].[Group Name].[Group Name]
*
[FRR Group Matrix].[FRRCode].[FRRCode],
[Measures].[Approved wk to wk %]
),
[Measures].[Approved wk to wk %],
BDESC
)
MEMBER [Measures].[Approved wk to wk Rank] AS
RANK (
(
[FRR Group Matrix].[Group Name].CurrentMember,
[FRR Group Matrix].[FRRCode].CurrentMember
),
[X],
[Measures].[Approved wk to wk %]
)
Related
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 I can calculate MTD for current month in last year? Below query returns total [Net Sales Amount] for 12.2015, but need to have sales from 01.12.2015 to 09.12.2015(Today).
SUM(
MTD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
)
)
,[Measures].[Net Sales Amount]
)
I think you need to use HEAD of the member you're finding:
SUM(
HEAD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
).CHILDREN,
, 9
)
,[Measures].[Net Sales Amount]
)
The above is assuming that in the design of your cube Dates are the children of Month.
You need to make the 9 dynamic - do you have future dates in your cube?
If you do not have future dates then this could work:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
Count(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
If you do have future dates then maybe the following:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
count(
NONEMPTY(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
)
Then one of the above can feed into the previous:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
COUNT(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
MEMBER [Measures].[PrevYearMTD] AS
SUM(
HEAD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
).CHILDREN,
, [Measures].[NumDaysInCurrentMonth]
)
,[Measures].[Net Sales Amount]
)
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
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.
I am new to MDX queries. I have the following query and would like to limit the results to only show records where the Margin Pct is > 0. Any help would appreciated.
WITH
MEMBER [Measures].[Margin Pct] as ([Measures].[Mgmt Margin Excluding Markup]/[Measures].[Net Sales])*100,format_string="0.0"
MEMBER [Measures].[Mgmt Margin] as [Measures].[Mgmt Margin Excluding Markup],format_string="0.0"
MEMBER [Measures].[Mgmt Cost Unit] as [Measures].[Mgmt Cost Unit Excluding Markup],format_string="0.00"
MEMBER [Measures].[FOBPrce] as [Measures].[FOB Price],format_string="0.00"
MEMBER [Measures].[CommUnt] as [Measures].[Comm/Unit],format_string="0.000"
MEMBER [Measures].[RebUnt] as [Measures].[Reb/Unit],format_string="0.00"
MEMBER [Measures].[FrtUnt] as [Measures].[Frt/Unit],format_string="0.00"
MEMBER [Measures].[PriceUnt] as [Measures].[Price/Unit],format_string="0.00"
SELECT NON EMPTY {
[Measures].[Rpt Inv Shp Date],
[Measures].[Lbs Shipped],
[Measures].[Net Sales],
[Measures].[FOBPrce],
[Measures].[CommUnt],
[Measures].[RebUnt],
[Measures].[FrtUnt],
[Measures].[PriceUnt],
[Measures].[Mgmt Cost Unit],
[Measures].[Mgmt Margin],
[Measures].[Margin Pct]
} ON COLUMNS, NON EMPTY {
(
[Item].[Group Sort].[Group Sort],
[Item].[Form Sort].[Form Sort],
[Item].[Specie Sort].[Specie Sort],
{[Item].[Group thru Item ID].[Group].ALLMEMBERS},
[Shrimp Group].[Shrimp Group].[Shrimp Group Name].ALLMEMBERS ,
{[Item].[Form].[Form].ALLMEMBERS},
[Item].[Meat - In Shell].[Meat or Inshell].ALLMEMBERS ,
[Item].[Super Specie].[Super Specie].ALLMEMBERS ,
{[Item].[Species].[Species].ALLMEMBERS},
{[Item].[Item ID].[Item ID].ALLMEMBERS},
[Item].[Desc-ItemID].[Item ID Description].ALLMEMBERS ,
[Item].[Package Type].[Packaging].ALLMEMBERS ,
{[Brand].[Brand].[Brand Name].ALLMEMBERS},
{[Warehouse].[Warehouse].[Warehouse Code].ALLMEMBERS},
[Order Invoice Lot].[Order-Invoice-Lot].[Lot].ALLMEMBERS ,
{[Customer Account Number].[Customer Account No].Levels(1)},
{[Ship To Customer].[Customer Name].Levels(1)},
{[Sales Person].[Person].Levels(1)},
[Order Invoice Lot].[Sales Order].[Sales Order].ALLMEMBERS ,
[Order Invoice Lot].[Invoice].[Invoice].ALLMEMBERS
)
} DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS FROM (
SELECT StrToSet( '{[Breaded Group].[Breaded Group].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Inventory Category].[Inventory Category].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Sold To Customer].[Customer Buying Group].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Ship To Customer Sales Group].[Ship To Customer Sales Group].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Sold To Customer].[Customer Legal Group].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Country Of Origin].[Long Name].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Is Sample].[Sample].[Description].[Regular]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Invoicing Status].[Invoicing Status-Detail].[Detail].[Sale Only],[Invoicing Status].[Invoicing Status-Detail].[Detail].[Credit Only]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Invoice Date].[Fiscal Year-Quarter-Month].[Fiscal Month].[Jul-FY13]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Sold To Customer].[Name].[All]}' ,CONSTRAINED ) ON COLUMNS FROM (
SELECT StrToSet( '{[Is NRV].[NRV].[All]}' ,CONSTRAINED )
ON COLUMNS FROM [FishTrackerReporting] ) ) ) ) ) ) ) ) ) ) )
I have tried to use a where clause against the [Measures].[Margin Pct] but get this error:
The WHERE clause function expects a tuple set expression for the argument. A string or numeric expression was used.
I also tried to use a filter after the on columns part of the query but get out of memory issues so I think I am missing something.
Too bad the reference of MDX is not the best. You can use HAVING or FILTER to achieve what you want. I'd go with HAVING since it's easier to use.
Please have a look here and find the last example.