Running total only covering range of cells with data - ssas

Using the illustrated mockup
(Note not all DimB members show so the total for DimA is larger than the sum of the displayed DimB, ignore this):
Query is showing (months,revenue) on 0, (dima,dimb) on 1 from cube
I would like some assistance in creating the calculated member that would calculate the running total across "Months" here (not a real time dimension).
Earlier i was using this one, but it was wrong on so many levels:
[Measures].[Accumulated Revenue] =
IIF(
([DimMonths].[Months].CurrentMember,[Measures].[Revenue]) = 0
AND ([DimMonths].[Months].CurrentMember.NextMember,[Measures].[Revenue]) = 0
,
IIF(
AGGREGATE({
[DimMonths].[Months].CurrentMember :
[DimMonths].[Months].Parent.LastChild
},[Measures].[Revenue]) = 0
,
NULL
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember.PrevMember
}
,[Measures].[Revenue])
)
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember
}
,[Measures].[Revenue])
)

Sounds like a job for a "scoped assignment". Basically, using a scoped assignment, you can overwrite the value of your calculated measure along the [Member_DimA_01] slice so that these values represent a running total instead of a sum of children.
Here's a good tutorial from Chris Webb on scoped assignments to help get you started...
Edit: here's a template for the running total calculation...
WITH
SET [Months] AS
{
[Date].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Month].&[2011 - Dec]
}
MEMBER [Measures].[Running Total] AS
SUM(
{
[Date].[Calendar Hierarchy].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Hierarchy].CurrentMember
}
,[Measures].[Revenue]
)
SELECT
NON EMPTY{
[Months]
} ON 0,
NON EMPTY{
[DimA].[Member].Allmembers *
[DimB].[Member].Allmembers
} ON 1
FROM
[<<cube name>>]
WHERE
[Measures].[Revenue Running Total]

Related

MDX: sum over time with range in rows

I have a day level in my time dimension.
I want to output the sum/avg for a selected range of days like in the following statement:
WITH
MEMBER measures.[sum1] AS
Sum([Measures].[Menge_Artikel_Stk])
MEMBER measures.[sum2] AS
Sum
(
[D_Datum].[Datum].[Tag]
,[Measures].[Menge_Artikel_Stk]
)
SELECT
{
[Measures].[stock]
,[Measures].[sum1]
,[Measures].[sum2]
} ON 0
,NON EMPTY
CrossJoin
(
{[D_item].[itemno].[itemno].MEMBERS}
,{
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
}
) ON 1
FROM [Cube];
My goal is to show the sum/avg along the date-dimension filtered on rows.
Instead of 40/1653 i want sum to display 250 for the sum or 35,7 for the average. (1653 is obviously the sum of the entire day level). I want to add this calculated member to an Excel-Sheet. Thus the time range set is variable.
To get the sum/avg rows across the specific range you can do something like this:
WITH
MEMBER measures.[sum1] AS
Sum([Measures].[Menge_Artikel_Stk])
MEMBER measures.[sum2] AS
Sum
(
[D_Datum].[Datum].[Tag]
,[Measures].[Menge_Artikel_Stk]
)
MEMBER [D_Date].[Date].[All].[DaySum] AS
Sum
(
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
)
MEMBER [D_Date].[Date].[All].[DayAvg] AS
Avg
(
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
)
SELECT
{
[Measures].[stock]
,[Measures].[sum1]
,[Measures].[sum2]
} ON 0
,NON EMPTY
CrossJoin
(
{[D_item].[itemno].[itemno].MEMBERS}
,{
{
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
}
,[D_Date].[Date].[All].[DaySum]
,[D_Date].[Date].[All].[DayAvg]
}
) ON 1
FROM [Cube];
You can use the Axis function to define the current set on your axis:
WITH
MEMBER measures.[sum] AS
Sum(
Axis(1),
[Measures].[Menge_Artikel_Stk]
)
MEMBER measures.[avg] AS
AVG(
Axis(1),
[Measures].[Menge_Artikel_Stk]
)
SELECT
{[Measures].[Menge_Artikel_Stk],[Measures].[sum],[Measures].[avg]} ON 0,
NON EMPTY {[D_Date].[Date].[day].[30.01.2017]:[D_Date].[Date].[Day].[05.02.2017]} ON 1
FROM [Cube];

With MDX hos to select first row?

I am using sharepoint report builder.
In my data (se picture below) - I would like to get all the first row - the ones with yellow.
How do i do that.
Here is the MDX code. What should I write to get the yellow rows?
SELECT
NON EMPTY
{[Measures].[Antal unikke brugere - Visiteret Tid]} ON COLUMNS
,NON EMPTY
{
[Borger].[Anonym Borgernøgle DPR].[Anonym Borgernøgle DPR].ALLMEMBERS*
[SundhedOgOmsorg - Ydelse].[Ydelse].[Ydelse].ALLMEMBERS*
[Kalender].[År].[År].ALLMEMBERS*
[Kalender].[Måned].[Måned].ALLMEMBERS
}
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
ON ROWS
FROM
(
SELECT
{
[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.1 Hjemmetrænerforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.2 Komb. Hjemmetræner & Terapeutforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.3 Komplekse Rehabiliteringsforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.7. hverdagsrehab. revis.gr. m. tp.]
} ON COLUMNS
FROM
(
SELECT
{[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]} ON COLUMNS
FROM [FrbLis]
)
)
WHERE
[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]
CELL PROPERTIES
VALUE
,BACK_COLOR
,FORE_COLOR
,FORMATTED_VALUE
,FORMAT_STRING
,FONT_NAME
,FONT_SIZE
,FONT_FLAGS;
You could try using one of the following iterative mdx functions:
Generate - https://msdn.microsoft.com/en-us/library/ms145526.aspx
Filter - https://msdn.microsoft.com/en-us/library/ms146037.aspx
To use filter is a little more convoluted as you need to specify specific tuples based on their relative positions. Generate is a little more straightforward. I will try to provide an example against the MS AdvWrks cube.
I think this is relatively similar to your situation:
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,NON EMPTY
[Product].[Product Categories].[Product]
*
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
} ON 1
FROM [Adventure Works];
You would like the rows I've marked in red (there are lots of products with only 1 row)
So if we now apply the following multi-dimensional expression to the cube:
WITH
SET [prodSet] AS
[Product].[Product Categories].[Product]
SET [prodDtSet] AS
Generate
(
[prodSet] AS P
,Head
(
P.Current
*
NonEmpty
(
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
}
,(
P.Current
,[Measures].[Internet Sales Amount]
)
)
)
)
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,[prodDtSet] ON 1
FROM [Adventure Works];
We get the results required:
Are you able to adapt my example to your context?
I will have a further play and supply a solution using Filter (it'll be, in a way, a little more complicated than the Generate approach)
Here is an approach using Filter:
WITH
SET [prodSet] AS
[Product].[Product Categories].[Product]
SET [prodDtSet] AS
NonEmpty
(
[prodSet]
*
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
}
,[Measures].[Internet Sales Amount]
)
SET [prodDtSetFiltered] AS
Filter
(
[prodDtSet]
,
(NOT
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 1).Item(0)
IS
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 2).Item(0))
OR
[prodDtSet].CurrentOrdinal = 1
)
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,[prodDtSetFiltered] ON 1
FROM [Adventure Works];
Results are as following:

How to mimic SQL subtraction of results from two different queries in mdx

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

MTD Function not working with SCOPE

SCOPE ([Measures].[Net IMS Volume]);
( [Time].[Time Calculations].[MTD] )
= SUM(
MTD([Time].[Time Hierarchy 1].CURRENTMEMBER)
,[Time].[Time Calculations].[Current Time]
);
END SCOPE;
I was expecting my MTD to be displayed across the dates of the month. but the result is that I just get data at the Month Level.
When I do the same thing over at SSMS w/ the ff.:
WITH MEMBER [Time].[Time Calculations].MIKE2 AS
SUM
(
MTD([Time].[Time Hierarchy 1].CURRENTMEMBER)
,[Time].[Time Calculations].[Current Time]
)
SELECT
{
([Time].[Time Calculations].[MTD],[Measures].[Net IMS Volume])
,([Time].[Time Calculations].MIKE2,[Measures].[Net IMS Volume])
} ON 0
,[Time].[Time Hierarchy 1].[Date] ON 1
FROM [My Cube];
I get data at Date Level. I'm experiencing this on YTD function also.
Your time dimensions may not be typed correctly. Specific typing is required for the YTD and MTD to function as expected.
MSDN reference to YTD function: https://msdn.microsoft.com/en-us/library/ms146039.aspx
In the "remarks" section of the definition:
If a member expression is not specified, the default is the current
member of the first hierarchy with a level of type Years in the first
dimension of type Time in the measure group.
The Ytd function is a shortcut function for the PeriodsToDate function where the Type
property of the attribute hierarchy on which the level is based is set
to Years. That is, Ytd(Member_Expression) is equivalent to
PeriodsToDate(Year_Level_Expression,Member_Expression). Note that this
function will not work when the Type property is set to FiscalYears.
You could test if this is your problem by converting to the use of PeriodsToDate:
WITH MEMBER [Time].[Time Calculations].MIKE2 AS
SUM
(
PeriodsToDate(
[Time].[Time Hierarchy 1].[Month Level]
, [Time].[Time Hierarchy 1].CURRENTMEMBER
)
,[Time].[Time Calculations].[Current Time]
)
SELECT
{
([Time].[Time Calculations].[MTD],[Measures].[Net IMS Volume])
,([Time].[Time Calculations].MIKE2,[Measures].[Net IMS Volume])
} ON 0
,[Time].[Time Hierarchy 1].[Date] ON 1
FROM [My Cube];

MDX - TopCount plus 'Other' or 'The Rest'

I have created an MDX query which calculates the TOP 10 ZipCodes (according to my Patient Stay measure) as such:
WITH
MEMBER [Discharge Date].[Y-M-D].[ Aggregation] AS 'AGGREGATE( EXISTING { [Current Month] } )', SOLVE_ORDER = 0
SELECT
NON EMPTY { [Measures].[Patient Stays] }
ON COLUMNS,
TOPCOUNT({ ORDER( HIERARCHIZE( { [Patient].[ByZipcode].[All].CHILDREN } ), ( [Measures].[Patient Stays] ), BDESC ) }, 10)
ON ROWS
FROM [Patient Stay]
WHERE ( [Discharge Date].[Y-M-D].[ Aggregation], [Facility].[ByAffiliation].CURRENTMEMBER, [Facility].[ByRegion].CURRENTMEMBER )
This query is used to populate a PerformancePoint 100% Stacked Bar chart. The client has asked that since this is a !00% based chart, we lump the rest of the zip codes into an "Other" field, such that there should be 11 values: one for each of the top 10, and an eleventh which is a sum of the remaining Zip Codes.
I am an extreme novice to MDX, but this doesn't souund like it should be impossible. Does anyone have any ideas or suggestions?
I'll do my best with untested code, so here goes:
WITH
MEMBER [Discharge Date].[Y-M-D].[ Aggregation] AS 'AGGREGATE( EXISTING { [Current Month] } )', SOLVE_ORDER = 0
SET [Top10ZipCodes] AS
(TOPCOUNT({ ORDER( HIERARCHIZE( { [Patient].[ByZipcode].[All].CHILDREN } ), ( [Measures].[Patient Stays] ), BDESC ) }, 10))
MEMBER [Patient].[ByZipCode].[OtherZipCodes] AS
(AGGREGATE({EXCEPT([Patient].[ByZipCode].Members, [Patient].[ByZipCode].[Top10ZipCodes])}))
SELECT
NON EMPTY { [Measures].[Patient Stays] }
ON COLUMNS,
{[Top10ZipCodes], [Patient].[ByZipCode].[OtherZipCodes]}
ON ROWS
FROM [Patient Stay]
WHERE ( [Discharge Date].[Y-M-D].[ Aggregation], [Facility].[ByAffiliation].CURRENTMEMBER, [Facility].[ByRegion].CURRENTMEMBER )
What this does is creates a set of your top 10 ZIP codes, and then aggregates (different than sum!!!) all the ZIP codes, with the exception of your top 10.
Also, if this is a common set (top 10 ZIP codes), you may want to make a set on the cube, where you can reuse it ad nauseum, without having to change every MDX query you have.
Cheers,
Eric