MDX sum a previous month - sql

I have created a cube with many different aggregations and any summing I do is within MDX. I am modeling lottery behavior based on previous drawings. Here is my current code:
WITH
SET [Alpha And Beta And Theta] AS
NONEMPTY (
{ [Dwtbl Dim Test Alpha].[Alpha PK].MEMBERS } *
{ [Dwtbl Dim Beta].[Beta PK].MEMBERS } *
{ [Dwtbl Dim Theta].[Theta PK].MEMBERS }
)
MEMBER Measures.TotalHits AS
SUM ( [Alpha And Beta And Theta]
, COALESCEEMPTY([Measures].[Hits],0)
)
MEMBER [Measures].[PrevMonth_TotalHits] AS
(ParallelPeriod ([Date].[CalendarYear].[Month NK]
, 1
, [Date].[CalendarYear].Currentmember
)
,[Measures].[TotalHits]
)
SELECT
{
[Measures].[TotalHits],
[Measures].[PrevMonth_TotalHits]
} ON COLUMNS
FROM [cubAgents]
WHERE ( [Date].[Year].[2013],
[Date].[Month NK].[7])
Now, when I pass in July, the code works as expected; I get hit counts from July and June. However, when I pass in August [8] which has not occurred yet, I get null for both current and previous month.
Why does this happen? Well, my set [Alpha And Beta And Theta] is a big nonempty crossjoin, with each dimension not occurring since it is in the future. If I remove the nonempty, it will work just fine ... but take 3 minutes to complete. I have spent too much time on this and I guess it is time to reach out to the experts.
Perhaps one method would be to directly sum my [Hits] measures for a previous month as opposed to using parallelPeriod, something like
MEMBER [Measures].[PrevMonth_Hits] AS
SUM ( {[Alpha And Beta And Theta]*[Date].[CalendarYear].Currentmember.LAG(1)}
, COALESCEEMPTY([Measures].[Hits],0)
)
This doesn't work.
Any help is greatly appreciated. Thanks!

Related

MDX Calculated Member Performance Issue

SELECT NON EMPTY {
[Measures].[Production_Volume]
} ON COLUMNS,
NON EMPTY { (
[Make].[Make ID].[Make ID].ALLMEMBERS
* [Model].[Model Hierarchy].[MDL].ALLMEMBERS
* [Customer].[Customer ID].[Customer ID].ALLMEMBERS
) } ON ROWS
FROM [Model_Cube]
This query is taking 10 min
[Measures].[Production_Volume] is a calculated member in the cube, if I put the definition of this member directly in the query it's taking much lesser time.
WITH MEMBER [Measures].[Production_Volume] AS
([Measures].[Model Count],
([Status].[Status Type].&[T]
,[Mode].[Mode Type].&[A])
)
+ Sum(
([HYBRID_MODELS]
,[Status].[Status Type].&[C]
,[Mode].[Mode Type].&[A])
,[Measures].[Model Count]
)
SELECT NON EMPTY {
[Measures].[Production_Volume]
} ON COLUMNS,
NON EMPTY { (
[Make].[Make ID].[Make ID].ALLMEMBERS
* [Model].[Model Hierarchy].[MDL].ALLMEMBERS
* [Customer].[Customer ID].[Customer ID].ALLMEMBERS
) } ON ROWS
FROM [Model_Cube]
this query is taking 4 sec
Unable to understand the difference between the two, I ran the profiler but couldn't find any difference, except that the first query showed flight recorder snapshot events second query didn't.
The problem was how I created named sets "[HYBRID_MODELS]". I changed them from DYNAMIC to STATIC this helped. Another change I did was replace -{} with the EXCEPT() function. These both changes reduced query time from 30min to 1min!
Hope this helps someone in need :)

DAX Moving Average Based on 4 Level Index

I have trouble calculating MA for products' prices. Data is in the following format:
Region has municipalities, products are sold there falling into certain categories by dates on a weekly basis, and not all weeks are filled due to seasonality.
I found a ranking formula and adjusted based on these 4 criteria. Here is the DAX expression for ranking (calculated column):
index2 =
RANKX (
FILTER (
_2017,
EARLIER ( _2017[RegionName] ) = _2017[RegionName] &&
EARLIER ( _2017[MunicipalityName] ) = _2017[MunicipalityName] &&
EARLIER (_2017[ProductCategoryName] )= _2017[ProductCategoryName] &&
EARLIER ( _2017[ProductName] ) = _2017[ProductName]
),
_2017[StartDateTime],
,
ASC
)
After a change in product name, the index resets. All is good till here. But when I try to add any kind of running total according to this index, it seems to calculate prices' sum for all products, giving the same result at index reset and so on for every product.
Here are some measures I've tried:
cummulatives =
VAR ind = MAX(_2017[index2])-3
VAR m1=
CALCULATE(
SUM(_2017[SellingPrice]),
FILTER(
ALL(_2017),
_2017[index2]<=ind))
VAR m2=
CALCULATE(
COUNT(_2017[SellingPrice]),
FILTER(
ALL(_2017),
_2017[index2]<=ind))
RETURN m2
Attached is an image of the table. Any help would be much appreciated. Thanks!
If you want the cumulative sum to reset with a new ProductName, then that has to be part of your filter context. You've removed that context using the ALL() function.
You can either put it back into the filter context or else not remove it in the first place. I would suggest the latter by using ALLEXCEPT(_2017, _2017[ProductName]) instead of ALL(_2017)

How To Get All Items Created or Still Open For A Given Time

I am working with a system were items are created (postDate dimension) and closed (endDate dimension). The endDate column is always populated with the last time the item was seen. An item is considered closed in a certain time if its last seen date is before the date you are querying. Each row in the fact table has the item, postDate, endDate, locationID, and some other dimensions used for aggregations. What I am trying to accomplish is getting all items still active for a given time frame. For example I want to know all items posted in November 2008 or before November 2008 that has not yet closed. In SQL it would look something like:
SELECT C.geoCountyArea,TM.CalendarYear,COUNT(DISTINCT a.itemid)
FROM [dbo].[factTable] a
JOIN dbo.dimDate AS TM
ON TM.DateKey BETWEEN postDate AND endDate
JOIN [dbo].[dim_geography] C
ON A.geographyID=C.geographyID
WHERE C.geoCountyArea = '1204000057'
AND TM.CalendarYear = 2008 AND TM.MonthNumberOfYear = 11
GROUP BY C.geoCountyArea,TM.CalendarYear
ORDER BY C.geoCountyArea,TM.CalendarYear
This returns 27,715 which is expected. Now, in MDX this looks like:
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:[PostDate].[Month Name].&[2008]&[11]} * {[EndDate].[Month Name].&[2008]&[11]:NULL},
[Measures].[Fact_itemCount]
)
SELECT NON EMPTY (
Measures.[itemCount]
) ON 0,
NON EMPTY (
{[PostDate].[Month Name].&[2008]&[11]},
{[Geography].[Geo County Area].&[1204000057]}
)ON 1
FROM [Cube];
This returns 27,717 - which is 2 more than the SQL version that could be due to items with no end Date posted. Now, the complication comes when I want to get more than one explicit time - for example item count for all months in 2008 or item count for all years. I looked up methods to link a given param to another one via roll playing dimensions and came across this link. I altered my script so it looks like:
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
,[PostDate].[Calendar])}
* {LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
, [EndDate].[Calendar]):NULL}
, [Measures].[Fact_itemCount]
)
SELECT {Measures.[jobCount]} ON 0,
NON EMPTY (
{[DATE].[Month Name].&[2008]&[11]},
{[Geography].[Geo County Area].&[1204000057]}
)ON 1
FROM [Cube];
This, however, returns only the items created in November 2008 - value of 14,884. If I add in other months I do get individual counts for each month but, again, these are just the items created in those months.
How do I get the "active" item count for a given month/year/quarter without having do explicitly declare the time values in the AGGREGATE?
Can you use NonEmpty?
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:
NONEMPTY(
[PostDate].[Month Name].MEMBERS //<<AMEND TO EXACT STRUCTURE USED IN YOUR CUBE
,[DATE].[Calendar].CURRENTMEMBER
).ITEM(0).ITEM(0)}
* {NONEMPTY(
[EndDate].[Month Name].MEMBERS //<<AMEND TO EXACT STRUCTURE USED IN YOUR CUBE
,[DATE].[Calendar].CURRENTMEMBER
).ITEM(0).ITEM(0): NULL}
, [Measures].[Fact_itemCount]
)
...
This ended up being the solution that provided valid results (tested against SQL calls against the warehouse tables):
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:LINKMEMBER([Post Date].[Calendar],
[Post Date].[Calendar])}
* {LINKMEMBER([Post Date].[Calendar],
[End Date].[Calendar]):NULL},
[Measures].[Fact_itemCount]
)
SELECT {Measures.[itemCount]} ON 0,
NON EMPTY (
{[Post Date].[Month Name].Children},
{[Geography].[Geo County Area].&[1204000057]}
)
FROM [Cube]
Not that I am doing LINKMEMBER against the post and end dates - not against the global Date measure.

Last Available value MDX

I have a requirement where in i am to extract data from a cube, within the SSRS dataset using the query builder ,with the time dimension in the result set, across a range of dates. The conditions are
The measures are to be displayed for each day of the date range.
The sub total row should have the last available measures value for that time range.
There is a time filter (currently a single date filter with a multi select option).
my MDX is as below.
The measure has a 'Sum' as the aggregation type.
I have a calculated measure with the scope defined as below.
SCOPE([MEASURES].[Measure1]);
SCOPE([Date].[Date].MEMBERS);
THIS = TAIL(EXISTING ([Date].[Date].MEMBERS),1).ITEM(0) ;
END SCOPE;
END SCOPE;
This above scope statement works perfectly. however, when i select in more that one date member this query slows WAYYYYYYY down. Performance numbers are
Across 1 date - 4 seconds
Across 2 dates - 22 minutes
Across 3 dates - unknown (in Hours)
This drastic degradation in performance goes away if i remove the scope statement, which makes me thing that there should be a better way to do the same. the final report query is as below.
SELECT
NON EMPTY
{[Measures].[Measure1]} ON COLUMNS
,NON EMPTY
{ [Dimension1].[Dimension1].[Dimension1].ALLMEMBERS*
[Dimension2].[Dimension2].[Dimension2].ALLMEMBERS*
[Dimension3].[Dimension3].[Dimension3].ALLMEMBERS*
[Date].[Date].[Date].ALLMEMBERS
} ON ROWS
FROM (
SELECT {[Date].[Date].&[2014-06-13T00:00:00]
,[Date].[Date].&[2014-06-16T00:00:00] } ON COLUMNS
FROM [Cube]
)
So the question again is, Is there a way to do the last available value part of the scope statement so as to have a better performance? Also, if there is another way to write the final mdx that would help the performance?.
Please let me know if there are anythings unclear regarding the question.
Thanks
Srikanth
The first optimization step would be to change your query to
SELECT
NON EMPTY
{[Measures].[Measure1]} ON COLUMNS
,NON EMPTY
{ [Dimension1].[Dimension1].[Dimension1].ALLMEMBERS*
[Dimension2].[Dimension2].[Dimension2].ALLMEMBERS*
[Dimension3].[Dimension3].[Dimension3].ALLMEMBERS*
{[Date].[Date].&[2014-06-13T00:00:00], [Date].[Date].&[2014-06-16T00:00:00] }
} ON ROWS
FROM [Cube]
Furthermore, I am not sure why you added the SCOPE([Date].[Date].MEMEBER); (probably Date].[Date].MEMBERS, actually). Maybe it helps to omit it and the corresponding END SCOPE.

MDX show all sales until now

i have a huge table of cashflows that means there are +int values for income and -int values for outcome.
I have MeasureGroup for Sum the amount of money.
I now want to display not only the sum of money per month but also the sum of all the past time until the current month so like that:
Month MoneyAmount Total
1 20 20
2 -10 10
3 5 15
4 -10 5
So i know for the first part its just like
select [Measures].[Money] on 0,
[Date].[Month].Members on 1
From MyCube
but how can i add the sum column?
i thought about something like SUM( { NULL : [Date].[Month].CurrentMember } , [Measures].[Money] ) but that didnt work as well :(
In MDX, the total is already there. You do not have to do complex calculations to get it.
But it depends on your exact hierarchy structure how the All member is called. If you have a date user hierarchy named [Date].[Date], and it has a month level named [Date].[Date].[Month], then the all member of the hierarchy would probably be called something like [Date].[Date].[All]. If [Month] is an attribute hierarchy of the Date dimension, then the "all member" would probably be called [Date].[Month].[All]. In the latter case, the all member would already be the first member of the set [Date].[Month].Members. As you are asking the question, I am assuming this is not the case, and you are using a user hierarchy. Then you could change your MDX query to
select [Measures].[Money] on 0,
Union([Date].[Month].Members, { [Date].[Date].[All] }) on 1
From MyCube
Please note that you can change the name of the All member in the property settings of a dimension when designing an Analysis Services dimension, hence I cannot know the definitive name without knowing the details of this setting in your cube. So you might have to adapt the name of the all member.
You can find this name out in SQL Server Management Studio in an MDX window as follows: open the hierarchy that you are using, and then open the "Members" node, below which you should find the "All Member". You can drag this into your MDX statement, and the proper name will appear there.
As in a running sum?
You need a calculated measure, like this:
With Member [Measures].[Running Sum] as Sum( ( [Date].[Months].Members.Item(0) : [Date].[Months].CurrentMember ), [Measures].[Money])
Select [Date].[Months].Members on Rows,
{[Measures].[Money], [Measures].[Running Sum] } on Columns
From [MyCube]