how to use MDX average function? - ssas

I am VERY new to mdx, and about to learn it. i got into trouble right now ,because i want to get average amount for each weekday between two dates.
For example between 1st of november and 1st of december there are 4 mondays, so average would be [Measures].[Amount] / 4, but i really cant figure out how to express this simple function in MDX
with member [Measures].[Avg] as
avg([Dim Date].[Day Of Week].[Day Of Week]
, [Measures].[amount])
SELECT NON EMPTY { ([Measures].[Avg]), ([Measures].[Amount])} ON COLUMNS,
NON EMPTY { ([Dim Date].[Day Of Week].[Day Of Week].ALLMEMBERS * [Dim Date].[Date Int].[Date Int].ALLMEMBERS )}
ON ROWS FROM ( SELECT ( { [Dim Client].[Common Client UID].&[{xx}] } )
ON COLUMNS FROM ( SELECT ( [Dim Date].[Date Int].&[20151115] : [Dim Date].[Date Int].&[20151215] )
ON COLUMNS FROM [ff]))
WHERE ( [Dim Client].[Common Client UID].&[{xx}] )
This query give me each weekday and all the dates which are bound to the specific weekday, and for each date there are an total amount.
like you can see my average is the same as total. I thought that i could just select all the weekdays between two date, find out for example how many mondays there are and divide it number with amount. but i couldnt figure that out either.
with member [Measures].[avg] as
avg([Dim Date].[Day Of Week].[Day Of Week], [Measures].[Amount])
SELECT NON EMPTY {[Measures].[avg], [Measures].[Amount]} ON COLUMNS, NON EMPTY { ([Dim Date].[Day Of Week].[Day Of Week].ALLMEMBERS )}
ON ROWS FROM ( SELECT ( { [Dim Client].[Common Client UID].&[{xx}] } )
ON COLUMNS FROM ( SELECT ( [Dim Date].[Date Int].&[20151115] : [Dim Date].[Date Int].&[20151215] )
ON COLUMNS FROM [ff]))
WHERE ( [Dim Client].[Common Client UID].&[{xx}] )
result :
How do i solve this?

What you really want is average amount over the dates corresponding to that weekday for the given date range.
You can just move the date range to the definition of calculated member, so that when value for a particular weekday is evaluated, the date range is also considered.
with member [Measures].[Avg] as
avg
(
[Dim Date].[Day Of Week].CURRENTMEMBER * {[Dim Date].[Date Int].&[20151115] : [Dim Date].[Date Int].&[20151215]}
,[Measures].[amount]
)
SELECT NON EMPTY { ([Measures].[Avg]), ([Measures].[Amount])} ON COLUMNS,
NON EMPTY [Dim Date].[Day Of Week].[Day Of Week].ALLMEMBERS * [Dim Date].[Date Int].[Date Int].ALLMEMBERS ON ROWS
FROM [ff]
WHERE ( [Dim Client].[Common Client UID].&[{xx}] )

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

The STRTOSET function expects a string or numeric expression for the 1 argument. A tuple set expression was used

I am very new to this whole MDX query thing. I have the following query which I am trying to execute but keep getting the following error:
Executing the query ...
Query (19, 16) The STRTOSET function expects a string or numeric expression for the 1 argument. A tuple set expression was used.
Execution complete
My query looks as follows:
SELECT
NON EMPTY { [Measures].[Effective Duration] } ON COLUMNS,
NON EMPTY { (
[Dim Cause Code].[Cause].[Cause].ALLMEMBERS *
[Dim Classification].[Classification].[Classification].ALLMEMBERS *
[Dim Date 1].[Full Date Alternate Key].[Full Date Alternate Key].ALLMEMBERS *
[Dim Location 1].[Work Center Name].[Work Center Name].ALLMEMBERS *
[Fact Process Downtime].[Start Datetime].[Start Datetime].ALLMEMBERS *
[Fact Process Downtime].[End Datetime].[End Datetime].ALLMEMBERS *
[Fact Process Downtime].[Id].[Id].ALLMEMBERS )
} DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS FROM (
SELECT ( STRTOSET({[Fact Process Downtime].[Is Virtual].&[False]}, CONSTRAINED) ) ON COLUMNS
FROM (
SELECT ( STRTOSET({[Dim Location 1].[Work Center].&[South32 Manganese.Mamatwan.DMS]}, CONSTRAINED) ) ON COLUMNS
FROM (
SELECT ( STRTOSET({[Dim Classification].[Classification].&[Scheduled Process]}, CONSTRAINED) ) ON COLUMNS
FROM (
SELECT ( STRTOSET({[Dim Date 1].[Month Fiscal Year].&[Jul/17]}, CONSTRAINED) ) ON COLUMNS FROM [FactDownTime])))) WHERE (
IIF( STRTOSET({[Dim Date 1].[Month Fiscal Year].&[Jul/17]}, CONSTRAINED).Count = 1, STRTOSET({[Dim Date 1].[Month Fiscal Year].&[Jul/17]}, CONSTRAINED), [Dim Date 1].[Month Fiscal Year].currentmember ),
IIF( STRTOSET(STRTOSET({[Dim Location 1].[Work Center].&[South32 Manganese.Mamatwan.DMS]}, CONSTRAINED).Count = 1, STRTOSET(STRTOSET({[Dim Location 1].[Work Center].&[South32 Manganese.Mamatwan.DMS]}, CONSTRAINED), [Dim Location 1].[Work Center].currentmember ),
IIF( STRTOSET({[Fact Process Downtime].[Is Virtual].&[False]}, CONSTRAINED).Count = 1, STRTOSET({[Fact Process Downtime].[Is Virtual].&[False]}, CONSTRAINED), [Fact Process Downtime].[Is Virtual].currentmember )
)))
You need to supply strings to this function strToSet is short for "String to Set"
https://msdn.microsoft.com/en-us/library/ms144782.aspx
So this is incorrect:
STRTOSET({[Fact Process Downtime].[Is Virtual].&[False]}, CONSTRAINED)
But this is correct
STRTOSET('{[Fact Process Downtime].[Is Virtual].&[False]}', CONSTRAINED))
The main use case for the strToSet function is when passing parameters into an mdx query from say SSRS so syntax like this is seldom used:
STRTOSET('{[Fact Process Downtime].[Is Virtual].&[False]}', CONSTRAINED))
If parameters are not involved then just get rid of the STRTOSET:
{[Fact Process Downtime].[Is Virtual].&[False]}
If you need to use parameters then check out this excellent recent answer from # alejandrozuleta:
MDX SSRS Parameter category chooses all sub category
If parameters are not important then your script can maybe get simplified to something like this:
SELECT
NON EMPTY [Measures].[Effective Duration] ON 0,
NON EMPTY
[Dim Cause Code].[Cause].[Cause].ALLMEMBERS *
[Dim Classification].[Classification].[Classification].ALLMEMBERS *
[Dim Date 1].[Full Date Alternate Key].[Full Date Alternate Key].ALLMEMBERS *
[Dim Location 1].[Work Center Name].[Work Center Name].ALLMEMBERS *
[Fact Process Downtime].[Start Datetime].[Start Datetime].ALLMEMBERS *
[Fact Process Downtime].[End Datetime].[End Datetime].ALLMEMBERS *
[Fact Process Downtime].[Id].[Id].ALLMEMBERS
ON 1
FROM
(
SELECT
[Fact Process Downtime].[Is Virtual].&[False] ON 0,
[Dim Location 1].[Work Center].&[South32 Manganese.Mamatwan.DMS] ON 1,
[Dim Classification].[Classification].&[Scheduled Process] ON 2,
[Dim Date 1].[Month Fiscal Year].&[Jul/17] ON 3
FROM [FactDownTime]
);

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}]
);

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:

Optimize a MDX Query

I am quite new to MDX and I need some help with this query.
Generate(
filter(
[Dim Products].[Product].[Product].members
*
[Dim Date].week.week.members,
[Measures].[Price]
),
nonempty(
topcount(
[Dim Price].[Price].[Price]
*
[Dim Products].[Product].currentmember
*
[Dim Date].week.currentmember,
1,
[Measures].[Price Count]
)
)
)
I am using the above Named Set in a dashboard tool (Dundas Dashboard) in order to retrieve the MODE (price value that repeats the most). It does show correct results however it is slow. It takes 2-3 seconds if there is a filter on a single week and takes about 6-7 seconds if there is no filter on week (shows data for all weeks). And this is in SSMS but the client tool takes even longer to get the result set, sometimes timing out.
After some tests it appears that the number of the rows in the fact table does not affect the performance, I've drastically decreased it but still the same. The performance increased, however, once I've decreased the number of members in 2 of the dimension tables - [Dim Price], [Dim Products]. Initially it was taking 20+ seconds to get result set but improved to 6-7 seconds once I've decreased the number of members as follows:
Table | Rows Before | Rows After
[Dim Price] | 2400 | 620
[Dim Products] | 1080 | 101
This makes me think there is a Cartesian Product between the 3 dimensions that is affecting the performance.
I need someone to advise how I can improve the query to increase the performance.
Try the EXISTING function before the NONEMPTY function like this:
Generate(
filter(
[Dim Products].[Product].[Product].members
*
[Dim Date].week.week.members,
[Measures].[Price] //<<<<<<<<<<SHOULD THIS NOT INCLUDE A CONDITION e.g. [Measures].[Price] > 0 ?
),
EXISTING nonempty(
topcount(
[Dim Price].[Price].[Price]
*
[Dim Products].[Product].currentmember
*
[Dim Date].week.currentmember,
1,
[Measures].[Price Count]
)
)
)
Attempt 2:
Generate(
filter(
NONEMPTY(
[Dim Products].[Product].[Product].members
*
[Dim Date].week.week.members,
[Measures].[Price]
)
),
EXISTING nonempty(
topcount(
[Dim Price].[Price].[Price]
*
[Dim Products].[Product].currentmember
*
[Dim Date].week.currentmember,
1,
[Measures].[Price Count]
)
)
)
Attempt 3:
GENERATE(
FILTER(
NONEMPTY(
[Dim Products].[Product].[Product].MEMBERS
*
[Dim Date].week.week.MEMBERS
),
[Measures].[Price] > 0
),
TOPCOUNT(
NONEMPTY(
EXISTING
[Dim Price].[Price].[Price]
*
[Dim Products].[Product].currentmember
*
[Dim Date].week.currentmember,
[Measures].[Price Count]
),
1,
[Measures].[Price Count]
)
)