We are facing an issue with one of the MDX queries.
If we use date selector in the Range in the where clause it takes 6 secs to execute else if we use comma as a separator, it takes around 1 sec.
Is there a way to modify the query and improve the performance by giving the range in the where clause. Kindly let us know your inputs on the same.
Example 1 With comma separator
WITH MEMBER Measures.X AS SUM({[User].[column].CURRENTMEMBER},[Measures].[# User Count])
SELECT NON EMPTY
UNION({[User].[column].[ALL]},
Generate(Hierarchize([User].[Column].[ALL])
AS [XL_Filter_Set_0], TopCount(Except(DrilldownLevel([XL_Filter_Set_0].Current
AS [XL_Filter_HelperSet_0],,0,INCLUDE_CALC_MEMBERS), [XL_Filter_HelperSet_0])
, 5, [Measures].[# User Count]))
)DIMENSION PROPERTIES PARENT_UNIQUE_NAME,HIERARCHY_UNIQUE_NAME ON ROWS , Measures.X ON COLUMNS
FROM [Activity] where
({[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2012],[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2013],
[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2014]},
{[Activity Type].[Activity Hierarchy].[All]})
Example 2 Without comma separator but we have given the range
WITH MEMBER Measures.X AS SUM({[User].[column].CURRENTMEMBER},[Measures].[# User Count])
SELECT NON EMPTY
UNION({[User].[column].[ALL]},
Generate(Hierarchize([User].[Column].[ALL])
AS [XL_Filter_Set_0], TopCount(Except(DrilldownLevel([XL_Filter_Set_0].Current
AS [XL_Filter_HelperSet_0],,0,INCLUDE_CALC_MEMBERS), [XL_Filter_HelperSet_0])
, 5, [Measures].[# User Count]))
)DIMENSION PROPERTIES PARENT_UNIQUE_NAME,HIERARCHY_UNIQUE_NAME ON ROWS , Measures.X ON COLUMNS
FROM [Activity] where
({[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2012]:[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2014]},
{[Activity Type].[Activity Hierarchy].[All]})
Regards,
Nancy
instead of using range in WHERE try use Range in FROM
from (
select ([Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2012]:[Date].[Fiscal Hierarchy].[Fiscal Year Name].&[2014]) on Columns From [Activity])
Related
How can I filter using values from two dimension in MDX?
The required result should include records where [Purchase Date].[Date] is before today minus number of years from [Accounting Date].[Year]. So, the result should include YoY records from today based on [Purchase Date].[Date] for each [Accounting Date].[Year] member.
I would like something like the following:
SELECT NON EMPTY [Measures].[Amount] ON 0,
NON EMPTY [Accounting Date].[Year].[Year].ALLMEMBERS ON 1
FROM [Tabular_Model]
WHERE (
NULL :
STRTOMEMBER("[Purchase Date].[Date].&["+ Format(DateAdd("YYYY", [Accounting Date].[Year].CURRENTMEMBER.MEMBER_VALUE - 2020, Now()),"yyyy-MM-ddT00:00:00") + "]")
)
But it fails with error: Execution of the managed stored procedure DateAdd failed with the following error: Microsoft::AnalysisServices::AdomdServer::AdomdException.
The syntax for 'All' is incorrect. (All).
Why CURRENTMEMBER.MEMBER_VALUE works for HAVING but not in my WHERE clause? What is the right way?
Try the following measure and query:
WITH
MEMBER [Measures].[Trailing Amount] as SUM({NULL :
STRTOMEMBER("[Purchase Date].[Date].&["+ Format(DateAdd("YYYY", [Accounting Date].[Year].CURRENTMEMBER.MEMBER_VALUE - 2020, Now()),"yyyy-MM-ddT00:00:00") + "]")}, [Measures].[Amount])
SELECT [Measures].[Trailing Amount] ON 0,
NON EMPTY [Accounting Date].[Year].[Year].MEMBERS ON 1
FROM [Tabular_Model]
If MDX doesn't perform as well as you hope, then you might consider adding the following DAX measure into your Tabular model. The following DAX query illustrates how to use it, but if you put this DAX measure into your model, you can query it with MDX queries and it should likely perform better than an MDX calculation:
define
measure 'Your Table Name Here'[Trailing Sales] =
VAR YearOffset = SELECTEDVALUE('Accounting Date'[Year]) - 2020
VAR NowDate = NOW()
VAR EndDate = DATE(YEAR(NowDate)+YearOffset,MONTH(NowDate),DAY(NowDate))
RETURN CALCULATE([Amount], 'Purchase Date'[Date] <= EndDate)
evaluate ADDCOLUMNS(ALL('Accounting Date'[Year]),"Trailing Sales",[Trailing Sales])
I already posted this problem many times, but unfortunately nobody could understand, I m sorry for my poor english :(
I reformulate ...
I have following fact table
I want to get records that match with a particular date and day of week (JOUR) in all dates range (DATE_DEB, DATE_FIN)
I can do that in SQL like this:
SELECT DATE_DEB,
DATE_FIN,
ID_HOR,
to_char(HR_DEB,'hh24:mi:ss') as HR_DEB,
to_char(HR_FIN,'hh24:mi:ss') as HR_FIN,
JOUR
FROM GRP_HOR HOR, GRP
WHERE GRP.ID_ACTIV_GRP = HOR.ID_ACTIV_GRP
AND TO_DATE('1998-01-08', 'YYYY-MM-DD') between DATE_DEB and DATE_FIN
AND 1 + TRUNC(TO_DATE('1998-01-08', 'YYYY-MM-DD')) - TRUNC(TO_DATE('1998-01-08', 'YYYY-MM-DD'), 'IW') = JOUR
So, I'll get 29 records (see below) which included in each range and match with the day of week (JOUR ), after that I want to enlarge them by hours (HR_DEB, HR_FIN).
The problem is, what's how the best way to do this ?
Create 2 date dimension and link them with DATE_DEB, DATE_FIN.
Create 2 Time dimension and link them with HR_DEB, HR_FIN.
How can I implement the between SQL clause in MDX ? Or geater than or Less than ?
Thank you in advance.
OUTPUT :
To specify a range of dates in MDX you just use the colon operator :
Here is the documentation on MSDN: https://learn.microsoft.com/en-us/sql/mdx/range-mdx?view=sql-server-2017
This is the example they give:
With Member [Measures].[Freight Per Customer] as
(
[Measures].[Internet Freight Cost]
/
[Measures].[Customer Count]
)
SELECT
{[Ship Date].[Calendar].[Month].&[2004]&[1] : [Ship Date].[Calendar].[Month].&[2004]&[3]} ON 0,
[Product].[Category].[Category].Members ON 1
FROM
[Adventure Works]
WHERE
([Measures].[Freight Per Customer])
I’m hoping someone can help me out with restructuring/rewriting my MDX query – I’m fairly new to MDX and only know enough to be dangerous. I am using Mondrian if that makes a difference.
Here is the stacked bar chart I am producing…
Injuries by Month and Category
And here is my query (simplified to remove all the stuff not relevant to this question)…
WITH
SET [Date Range] AS {${mdxStartDateParam}.Parent : ${mdxEndDateParam}.Parent}
MEMBER [Measures].[Month Name] as [Incident Date.YQMD].currentmember.parent.parent.name || "-" || [Incident Date.YQMD].currentmember.name
SET [Classification Month Set] AS (
Hierarchize(
ORDER(
Hierarchize(FILTER([Classification].[Classification].members,[Classification].CURRENTMEMBER IN {Descendants([Classification].[${paramInjClass}])})),
[Measures].[Injury Count],
BDESC
)
) * [Date Range]
)
SELECT {[Measures].[Injury Count], [Measures].[Month Name]} ON COLUMNS,
NON EMPTY [Classification Month Set] ON ROWS
FROM [Injury Analysis]
The problem I have is that my two date parameters (${mdxStartDateParam} and ${mdxEndDateParam}) can be any date at the [Day] level, while my chart X Axis is showing at the [Month] level, and even if the ${mdxStartDateParam} is midway through a month my query is returning all data for the month.
eg. If I have an Injury that occurred on February 2nd but my ${mdxStartDateParam} is [Incident Date.YQMD].[2017].[Q1].[Feb].[17], then that Injuryis being included in the chart.
Is there a way I can restructure my MDX so that the bar for February does not show all data for February, but only the data for Fenruary that is >= ${mdxStartDateParam} and <= ${mdxEndDateParam}?
Since the Mondrian doesn't support sub-queries, you can't use your Calendar hierarchy for both where clause and axis. Also there is no way to filter days and show month only on axis. So, if you have two separate hierarchies for Days and Months, you may use the following:
WITH
SET [Date Range] AS [YourDateDim].[YourHierarchyNotInDateParam].[MonthLevel].Members
MEMBER [Measures].[Month Name] as [Incident Date.YQMD].currentmember.parent.parent.name || "-" || [Incident Date.YQMD].currentmember.name
SET [Classification Month Set] AS (
Hierarchize(
ORDER(
Hierarchize(FILTER([Classification].[Classification].members,[Classification].CURRENTMEMBER IN {Descendants([Classification].[${paramInjClass}])})),
[Measures].[Injury Count],
BDESC
)
) * [Date Range]
)
SELECT {[Measures].[Injury Count], [Measures].[Month Name]} ON COLUMNS,
NON EMPTY [Classification Month Set] ON ROWS
FROM [Injury Analysis]
WHERE {${mdxStartDateParam}:${mdxEndDateParam}})
Otherwise you have to deal with shown days and group them after.
Without knowing anything about the dialect of MDX you're using, or being able to see the dimension structure, my guess is that the problem is with the definition of [Date Range]:
SET [Date Range] AS {${mdxStartDateParam}.Parent : ${mdxEndDateParam}.Parent}
If the two parameters are at the Day level, does .Parent return their parent months?
The solution might be to make the date range be a set of days:
SET [Date Range] AS {${mdxStartDateParam} : ${mdxEndDateParam}}
and then aggregate by month somehow.
I'm a newcomer to SQL MDX and don't know exactly how to achieve this.
I need to get data from my cube for the last X days from the last available data.
The following is my code:
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),30) } ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
The problem is the query returns the last 30 days where data exists, not the last 30 consecutive calendar days.
How can I change the query to get the results I want?
Try this. The only thing I changed is the select with the dates in it. Instead of asking for the last 30 days where there is data for the measures, I'm asking for the last day where there is data for the measures, getting that last item and then doing the lag of 29 days for the beginning of the date range and then without the lag (to the last day with data) for the end of the date range.
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).item(0).lag(29): TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).itm(0)} ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
Be aware that the way you have the query now will return the last day where there is data for both measures. If those two measures don't line up it might not provide what you want. For instance, if there is data through Dec 30 2013 on Fact Stays Count and data through Jan 5 2014 on Time Spent, it would return Dec 30 2013. If you want it to depend on both measures, you are good. If you want it to depend on one measures, you can switch it to be something like the below instead.
Tail(Filter([FK Date].[Date].[Date].MEMBERS.MEMBERS, [Measures].[Fact Stays Count] >0),1).item(0)
I have a filter that selects a specific date in my date dimension, This will be passed in as a parameter into the MDX query.
Filter([Date Dimension].[Calendar Year Hierarchy].[Actual Date].members,
[Date Dimension].[Actual Date].CurrentMember.Properties( "Name" ) = '2011-09-01 00:00:00.000')
I would now like to select the weeks and/or months in the hierarchy above that.
[Date Dimension].[Calendar Year Hierarchy].[Month]
[Date Dimension].[Calendar Year Hierarchy].[Calendar Week]
I have tried several functions without much luck such as .Parent and DrillupLevel
I could be using them wrong or in the wrong spot,
thanks for the help
You could use the function GENERATE to get all ascendants:
Generate
(
{Filter([Date Dimension].[Calendar Year Hierarchy].[Actual Date].members,
[Date Dimension].[Actual Date].CurrentMember.Properties( "Name" ) =
'2011-09-01 00:00:00.000')},
{Ascendants([Date Dimension].[Calendar Year Hierarchy].CurrentMember)}
)
Query using Adventure Works:
Select
{[Measures].[Internet Sales Amount]} On Columns,
{Generate(
{Filter([Date].[Calendar].[Date].members,[Date].[Calendar].CurrentMember.Properties("Name") = 'April 1, 2004')},
{Ascendants([Date].[Calendar].CurrentMember)})} On Rows
From [Adventure Works]
If you know the level you're looking for you can use MDX Ancestor function instead of parent:
Ancestor([Date Dimension].[Calendar Year Hierarchy].currentmember,
[Date Dimension].[Calendar Year Hierarchy].[Month])
If no, it's fine using parent function. Note, using properties is not the quickest method to filter (for very large sets).
Why not using to StrToMember MDX function ?
StrToMember( ... here build your member with a string ... )
or if you can edit you mdx directly creating the statement directly with the help of a string builder ?
so the answer i have at the moment is
Filter([Date Dimension].[Calendar Year Hierarchy].[Actual
Date].members, [Date Dimension].[Actual
Date].CurrentMember.Properties( "Name" ) = '2011-09-01 00:00:00.000')
.item(0).parent
using the .item[0] to get the item in the set
and the .parent to get that items parent (in my case i am actually calling it 3 times)
if anyone has any better ideas would love to here them.
You can use STRTOSET and for each input parameter replace ] with ].Parent, this way you will have set of parents.