I've got the following problem with my MDX statement. The previous element in the created set "[S_PrevDate]" is not accessible due to the where clause. The calculated member "x" returns an empty set. Without where-clause it is working fine.
#Month = "[Date].[Y-Q-M-D].[Month].&[201709]"
WITH
SET [S_PrevDate] AS
StrToMember(#Month, CONSTRAINED).PrevMember
MEMBER x AS
SetToStr([S_PrevDate])
SELECT x ON 0 FROM [cube]
WHERE StrToMember(#Month, CONSTRAINED)
In fact, selecting another month isn't working either. "x" remains empty:
WITH
SET [S_PrevDate] AS
[Date].[Y-Q-M-D].[Month].&[201708] -- August
MEMBER x AS
SetToStr([S_PrevDate])
SELECT x ON 0 FROM [cube]
WHERE [Date].[Y-Q-M-D].[Month].&[201709] -- September
What am I missing or how can I work around this issue? The set will be used in quite some calculations and needs to be created in the query scope.
Do really need a set? Try it:
WITH
MEMBER x AS
SetToStr([Date].[Y-Q-M-D].[Month].&[201708] )
SELECT x ON 0 FROM [cube]
WHERE [Date].[Y-Q-M-D].[Month].&[201709] -- September
What is the point of the WHERE clause in your script? WHERE happens very early in execution order of an mdx script - and creates the scope.
You have:
WITH
SET [S_PrevDate] AS
StrToMember(#Month, CONSTRAINED).PrevMember
MEMBER x AS SetToStr([S_PrevDate])
SELECT x ON 0
FROM [cube]
WHERE StrToMember(#Month, CONSTRAINED);
I don't understand why you cannot just drop the WHERE clause?
WITH
SET [S_PrevDate] AS
StrToMember(#Month, CONSTRAINED).PrevMember
MEMBER x AS SetToStr([S_PrevDate])
SELECT x ON 0
FROM [cube];
This might also be an alternative:
WITH
SET [MTH] AS
StrToSet("{" + #Month + "}", CONSTRAINED)
SET [S_PrevDate] AS
[MTH].ITEM(0).PrevMember
MEMBER x AS
SetToStr([S_PrevDate])
SELECT x ON 0
FROM [cube];
Related
in MDX I would like to create a select which returns a 2x2 array, filled with hard coded values.
Here is an attempt:
WITH
MEMBER a AS 1
MEMBER b AS 2
SET un AS { a , b }
SELECT { un} ON 0,
[Dim misc].[Gender].[(All)] ON 1
FROM [my cube]
it returns:
but I would like it to return an other row, with other values than 1,2.
You have solved half the problem already. However defining a set is not necessary.
You need to do the following
Use defaultmember,
Use Case
Define a dummy member for the dimension you use.
Instead of Set just define members.
Take a look at the example below based on adventure works.
with
member Column1Row1 as 1
member Column2Row1 as 2
member Column1Row2 as 3
member Column2Row2 as 4
member Column1 as case when [Product].[Product].currentmember is [Product].[Product].defaultmember then Column1Row1 else Column1Row2 end
member Column2 as case when [Product].[Product].currentmember is [Product].[Product].defaultmember then Column2Row1 else Column2Row2 end
member [Product].[Product].[Row2]
as [Product].[Product].defaultmember
select
{Column1,Column2} on 0,
{
[Product].[Product].defaultmember,
[Product].[Product].[Row2]}
on 1
from
[Adventure Works]
Result
I am new to MDX queries. I have written a query which uses lead function to get values for (Current Week plus 1) as a new column for each of the metrics. Basically comparing current week value with last week's value. Without the new members the query runs within seconds. After adding the new members it runs forever. Pls suggest ways to optimize this query
Thanks for help.
WITH
SET [Range] as strtomember
(" [Time].[Week].&["+ Format(DateAdd('d', - DatePart('w', Now(), 2), Now()+7), "yyyy-MM-ddT00:00:00")
+"]")
:strtomember
(" [Time].[Week].&["+ Format(DateAdd('d', - DatePart('w', Now(), 2), Now()+14), "yyyy-MM-ddT00:00:00")
+"]")
MEMBER [Measures].[SalesNew] as
CASE WHEN [Time].[Year].CURRENTMEMBER IS [Time].[Year].&[2019] THEN
sum([Time].[Day].CURRENTMEMBER.LEAD(7),[Measures].[Sales Prev])
ELSE null
END,FORMAT_STRING = "$#,###.00"
MEMBER [Measures].[Order UnitsNew] as
CASE WHEN [Time].[Year].CURRENTMEMBER IS [Time].[Year].&[2019] THEN
sum([Time].[Day].CURRENTMEMBER.LEAD(7),[Measures].[Order Units Prev])
ELSE null
END,FORMAT_STRING = "#,##0"
MEMBER [Measures].[Count of OrdersNew] as
CASE WHEN [Time].[Year].CURRENTMEMBER IS [Time].[Year].&[2019] THEN
sum([Time].[Day].CURRENTMEMBER.LEAD(7),[Measures].[Count of Orders Prev])
ELSE null
END,FORMAT_STRING = "#,##0"
SELECT
{ [Measures].[Sales],[Measures].[Sales Prev],[Measures].[SalesNew],[Measures].[Order Units],[Measures].[Order Units Prev],
[Measures].[Order UnitsNew], [Measures].[Count of Orders],[Measures].[Count of Orders Prev], [Measures].[Count of OrdersNew]} ON COLUMNS ,
[Range] *
[Time].[Day].[Day].ALLMEMBERS * -- 4
[Time].[Hour].ALLMEMBERS *
[Product].[Merch Dept].ALLMEMBERS *
[Product].[Class].ALLMEMBERS ON ROWS
FROM [Cube]
Your MDX looks pretty cool.
Optimizing MDX is a little bit black magic - you need to just try alternatives.
Initially I'd try:
1.Swapping in strToSet rather than the two strToMember functions.
2.Do you need the condition [Time].[Year].CURRENTMEMBER IS [Time].[Year].&[2019] ? Reason I ask is that [Range] seems to
already be 2019 and you cross-join to that set so do you need to
worry about 2019?
3.You can use a simple Tuple instead of the aggregate SUM
4.Maybe while testing it might be worth removing the format_strings - shouldn't make a difference but if so you can add back.
I've not tested the following so please excuse typos:
WITH
SET [DateSet] AS
strtoSet
(
"[Time].[Week].&["
+ Format(DateAdd('d', - DatePart('w', Now(), 2), Now()+7), "yyyy-MM-ddT00:00:00")
+ "]:[Time].[Week].&["
+ Format(DateAdd('d', - DatePart('w', Now(), 2), Now()+14), "yyyy-MM-ddT00:00:00")
+"]"
)
MEMBER [Measures].[SalesNew] AS
(
[Time].[Day].CURRENTMEMBER.LEAD(7)
,[Measures].[Sales Prev]
)
MEMBER [Measures].[Order UnitsNew] AS
(
[Time].[Day].CURRENTMEMBER.LEAD(7)
,[Measures].[Order Units Prev]
)
MEMBER [Measures].[Count of OrdersNew] AS
(
[Time].[Day].CURRENTMEMBER.LEAD(7)
,[Measures].[Count of Orders Prev]
)
SELECT
{
[Measures].[Sales]
,[Measures].[Sales Prev]
,[Measures].[SalesNew]
,[Measures].[Order Units]
,[Measures].[Order Units Prev]
,[Measures].[Order UnitsNew]
,[Measures].[Count of Orders]
,[Measures].[Count of Orders Prev]
,[Measures].[Count of OrdersNew]
} ON COLUMNS ,
[DateSet] *
[Time].[Day].[Day].ALLMEMBERS *
[Time].[Hour].ALLMEMBERS *
[Product].[Merch Dept].ALLMEMBERS *
[Product].[Class].ALLMEMBERS ON ROWS
FROM [Cube];
I wanted to do the trend analysis between the dates. For an instance current date- 30 days
30-60 days and so on.Below is the snippet of comparable sql query but same I wanted to do in MDX.
SQL
SELECT
ROUND
(
(
(
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-30) AND DATE(now())
)
-
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
)
)
/
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
) *100
)
,
0
) AS trend
MDX:
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SELECT
NON EMPTY {[Measures].[CONT_AMT_GROSS], [Measures].[CONT_AMT_NET]} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE [~FILTER]
As of now I have hard coded the dates, that will come from parameters.
I am facing difficulty in creating the second set and how to do subtraction between two sets in MDX.
You already have the logic on how to obtain sets of date corresponding to "last 30 days from now" and "last 60 to last 30 days from now". So, I am going to skip that part.
NOTE - You would have to use the parameter values while building these sets.
What you want to do here is first find the values corresponding to these sets of dates and then perform operations on them.
You can proceed like this -
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SET [Last30Days] AS
...
SET [Last60ToLast30Days] AS
...
MEMBER [~Last30Days - Now] AS
Aggregate
(
[Last30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Last60Days - Last30Days] AS
Aggregate
(
[Last60ToLast30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Measure] AS
([~Last30Days - Now]-[~Last60Days - Last30Days] )/([~Last60Days - Last30Days] * 100), format_string = '#,##0'
SELECT
NON EMPTY {
[Measures].[CONT_AMT_GROSS],
[Measures].[CONT_AMT_NET],
[~Measure]
} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
Format_String takes care of rounding.
Not sure if I totally agree with Sourav's answer as I think some form of aggregation will be needed; creating tuples with sets in them may raise an exception.
Here is a simple model, against AdvWrks, that is tested and will do a subtraction for you:
WITH
SET [Set1] AS
[Date].[Calendar].[Date].&[20060301]
:
[Date].[Calendar].[Date].&[20070308]
SET [Set2] AS
[Date].[Calendar].[Date].&[20070308]
:
[Date].[Calendar].[Date].&[20080315]
MEMBER [Date].[Calendar].[All].[Set1Agg] AS
aggregate([Set1])
MEMBER [Date].[Calendar].[All].[Set2Agg] AS
aggregate([Set2])
MEMBER [Date].[Calendar].[All].[x] AS
(
[Date].[Calendar].[All].[Set1Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[y] AS
(
[Date].[Calendar].[All].[Set2Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[x-y] AS
[Date].[Calendar].[All].[x] - [Date].[Calendar].[All].[y]
SELECT
{
[Date].[Calendar].[All].[x]
,[Date].[Calendar].[All].[y]
,[Date].[Calendar].[All].[x-y]
} ON 0
,[Product].[Category].[Category] ON 1
FROM [Adventure Works];
Reflecting against your code maybe something like the following:
WITH
SET [Set1] AS
[Created_Date.Created_Hir].[Created_On].[2014-04-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-04-30]
SET [Set2] AS
[Created_Date.Created_Hir].[Created_On].[2014-03-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-03-31]
MEMBER [Created_Date.Created_Hir].[All].[Set1Agg] AS
Aggregate([Set1])
MEMBER [Created_Date.Created_Hir].[All].[Set2Agg] AS
Aggregate([Set2])
MEMBER [Measures].[~Last30Days - Now] AS
(
[Created_Date.Created_Hir].[All].[Set1Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Last60Days - Last30Days] AS
(
[Created_Date.Created_Hir].[All].[Set2Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Measure] AS
([Measures].[~Last30Days - Now] - [Measures].[~Last60Days - Last30Days])
/
[Measures].[~Last60Days - Last30Days]
* 100
,format_string = '#,##0'
SET [~ROWS] AS
{
[Sales Order Attributes SO.Sales_order].[Sales Order ID].MEMBERS
}
SELECT
NON EMPTY
{
[Measures].[CONT_AMT_GROSS]
,[Measures].[CONT_AMT_NET]
,[Measures].[~Measure]
} ON COLUMNS
,NON EMPTY
[~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE
[~FILTER];
I'm trying to create a Calculated Member in my cube with where clause but couldn't figure how to achieve the proper result.
I created a calculated member "Outlook" using the below code to display only Forecast values.
CREATE MEMBER CURRENTCUBE.[Measures].[Outlook]
AS SUM(([Source Profile].[Source Profile Hierarchy].CurrentMember,
[Source Profile].[Profile Level01].&[Outlook]),
[Measures].[USD Amount]),
FORMAT_STRING = "#,##0;(#,##0)",
VISIBLE = 1 , DISPLAY_FOLDER = 'USD' , ASSOCIATED_MEASURE_GROUP = 'CARS';
Cube Result
Now I would like to filter the results dynamically based on another hidden dimension "Current_Month". This dimension always has current financial period value and it's corresponding outlook profile
Year_Month Outlook_Profile
2015010 10 + 2
Expected result should be "Outlook" measure showing value based on Current_Month dimension, which is '10 + 2' and rest of them should be 0
Expected result
Just to explain the requirement in SQL terms, I would like to achieve the below in MDX
Where Fact.Source_Profile=Dimension.Source_Profile
instead of
Where Fact.Source_Profile='10 + 2'
I'm not sure how to achieve this in Where Clause or by another means. I could see examples of hard coding values, like year.&[2015] but haven't seen one using dynamic values.
I found a solution myself and thought of sharing the same. Used StrToMember function to pass hidden dimension's member as a variable here.
CREATE MEMBER CURRENTCUBE.[Measures].[Outlook]
AS (
Sum
(
(
[Source Profile].[Source Profile Hierarchy].CurrentMember,
strtomember("[Source Profile].[Source Name].&[" + [Outlook Profile].[Outlook Profile].&[1].Member_Caption + "]")
)
,[Measures].[USD Amount]
)
),
FORMAT_STRING = "#,##0;(#,##0)",
VISIBLE = 1 , DISPLAY_FOLDER = 'USD' , ASSOCIATED_MEASURE_GROUP = 'CARS' ;
To give you a slight background to the problem, there are certain "users" who do certain "tasks" which are categorized into various types; one such type being "DSR". The requirement I am faced with is to find how many requests of type DSR the userid 033343 worked on for each month of year 2013.
What I would be needing is to get the count of the members in set of all the distinct requests a user (Userid = 033343) worked on in the year = 2013 and for the Request Type = DSR.
Below is what I tried at first:
WITH SET requests AS
EXISTING [Request].[RequestID].MEMBERS
MEMBER Measures.[Count033343] AS
DISTINCTCOUNT(requests)
SELECT Measures.[Count033343] ON 1,
[Calendar].[CalendarMonthName].CHILDREN ON 0 /*Values like January, February, etc. Not tied to Calendar Years*/
FROM [Model]
WHERE(
[User].[UserID].&[033343],
[Request Type].[Request Type Name].&[DSR],
[Calendar].[CalendarYear].&[2013]
)
But that didn't work. I got below result.
I figured, there is an issue with the set that I was building.
Then I moving the MDX to the Set definition. I thought it might make the code work faster as compared to having an extra set of tuple in WHERE clause.
WITH SET requests AS
EXISTS([Request].[RequestID].MEMBERS, (
[User].[UserID].&[033343],
[Request Type].[Request Type Name].&[DSR],
[Calendar].[CalendarYear].&[2013]
))
MEMBER Measures.[Count033343] AS
DISTINCTCOUNT(requests)
SELECT Measures.[Count033343] ON 1,
[Calendar].[CalendarMonthName].MEMBERS ON 0
FROM [Model]
But I was still getting the same result as above - 0 as the count for all the months!
Then, I thought of checking the set itself I was building(In the second example)
WITH SET requests AS
EXISTS([Request].[RequestId].MEMBERS, (
[User].[UserID].&[033343],
[Request Type].[Request Type Name].&[DSR],
[Calendar].[CalendarYear].&[2013]
))
SELECT [Measures].[Average of Late Tasks] ON 1,
requests ON 0
FROM [Model]
That proved two things.
1) The set was returning NULL values along with non null values.
2) There are indeed Request Ids returned from the set. So the count of Requests is definitely greater than 0 for the tuple specified.
I could use the NON EMPTY clause to remove the NON NULL values but, I don't want to use it as I read that it adds overhead.
As I have verified above that there are indeed requests for various users for all the months in 2013, why I am getting the count to be 0? Where am I going wrong? Why isn't the EXISTS and EXISTINGfunctionality working as expected? Isn't the set supposed to return only those Request IDs which exist for the condition? Is my understanding wrong?
EDIT
For #whytheq - With your final query, I got non-zero values
WITH MEMBER Measures.[x] AS
Count(
NONEMPTY(
[Request].[RequestId].MEMBERS
, {([Measures].[Average of Late Tasks])}
)
)
SELECT
Measures.[x] ON 0,
[Calendar].[CalendarYear].&[2013] ON 1
FROM [Model]
OUTPUT
x
2013 2
(Not tested) Does this still return zeros?
WITH SET [requests] AS
{([User].[UserID].&[033343],
[Request Type].[Request Type Name].&[DSR])}
* {[Measures].[Average of Late Tasks]} //<<<<try running with and without this line
* [Request].[RequestID].MEMBERS
MEMBER Measures.[Count033343] AS
DISTINCTCOUNT(requests)
SELECT
[Calendar].[CalendarMonthName].CHILDREN ON 0,
Measures.[Count033343] ON 1
FROM [Model]
WHERE(
[Calendar].[CalendarYear].&[2013]
)
How about the following?
WITH
MEMBER Measures.[Count033343] AS
DISTINCTCOUNT({[Request].[RequestID].[RequestID]})
SELECT
[Calendar].[CalendarMonthName].CHILDREN ON 0,
Measures.[Count033343] ON 1
FROM [Model]
WHERE(
[Calendar].[CalendarYear].&[2013],
[User].[UserID].&[033343],
[Request Type].[Request Type Name].&[DSR]
)
Maybe try this simpler query first and (if it works!) we can build up from this to try to locate the problem...
WITH MEMBER Measures.[x] AS
Count(
NONEMPTY(
[Request].[RequestId].MEMBERS
, {([Measures].[Average of Late Tasks])}
)
)
SELECT
Measures.[x] ON 0,
[Calendar].[CalendarYear].&[2013] ON 1
FROM [Model]