MDX - Sum one measure at leaf lvl where another measure exists at leaf lvl - mdx

I need to work out Stockturn at any lvl in an item hierarchy.
So far the calc is SUM the last 3 months [COGS] * 4 divided by [SOH] (SOH Value)
The below is embedded in a BI tool and works. It is in the Item grid and filters for every member in the Item dimension at the level display:
((SUM({.lag(3):.lag(1)}, ([Type].[Type].[Actual], [Measures].[Cogs]))) * 4) /
([Type].[Type].[Actual], [Measures].[SOH], )
What it needs changed/added is only returning [SOH] for Items where the [COGS] measure has values.
So if I have items that do not have COGS then do not include them:
Item
SOH
COGS
A
10
20
B
15
40
C
20
Do not include C as it will throw the calc.

The simplest approach - assuming you are using SSAS 2012 or newer - would be to use Divide instead of the division operator /:
Divide( ((SUM({.lag(3):.lag(1)}, ([Type].[Type].[Actual], [Measures].[Cogs]))) * 4),
([Type].[Type].[Actual], [Measures].[SOH], )
)
Divide returns NULL (empty value) instead of infinity when dividing by zero or null.
Edit: I see you want to avoid the calculation of the numerator is null or 0, not the denominator. In this case, you would use Iif:
IIF((SUM({.lag(3):.lag(1)}, ([Type].[Type].[Actual], [Measures].[Cogs])) <> 0,
((SUM({.lag(3):.lag(1)}, ([Type].[Type].[Actual], [Measures].[Cogs]))) * 4)
/
([Type].[Type].[Actual], [Measures].[SOH], )
, NULL)
Iif is a function with three arguments, a condition, the value to use if the condition is true, and the condition to use if the condition is false.

Related

DAX formula for - MAX of COUNT

I have the below dataset:
using the measure:
BalanceCount := COUNT(Balances[Balance])
which gives me the result:
However, I want the Grand Total to show the maximum amount of the BalanceCount, which is 2.
NewMeasure:=
MAXX(
SUMMARIZE(
FactTable
,FactTable[Account]
,FactTable[MonthEnd]
)
,[BalanceCount]
)
SUMMARIZE() groups by the columns specified, and MAXX() iterates through the table specified, returning the maximum of the expression in the second argument evaluated for each row in its input table.
Since the filter context will limit the rows of the fact table, we'll only have the appropriate subsets in each column/row grand total.
I found a solution that works for this particular case. It will not work if columns other than Account and MonthEnd are included in the filter context.
MaxBalanceCount:=
MAXX ( SUMMARIZE (
Balances,
Balances[Account],
Balances[MonthEnd]
),
CALCULATE ( COUNTROWS ( Balances ) )
)

select outliers based on sigma and standard deviation in sql

The sample data is like this.
I want select outliers out of 4 sigma for each class.
I tried
select value,class,AVG(value) as mean, STDEV(value)as st, size from Data
having value<mean-2*st OR value>mean+2*st group by calss
it seems does not work. Should I use having or where clause here?
The results I want is the whole 3rd row and 8th row.
When the condition you are looking at is a property of the row, use where i.e. where class = 1 (all rows with class 1) or where size > 2 (all rows with size > 2). When the condition is a property of a set of rows you use group by ... having e.g. group by class having avg(value) > 2 (all classes with average value > 2).
In this case you want where but there is a complication. You don't have enough information in each row alone to write the necessary where clause, so you will have to get it through a subquery.
Ultimately you want something like SELECT value, class, size FROM Data WHERE value < mean - 2 *st OR value > mean + 2*st; however you need a subquery to get mean and st.
One way to do this is:
SELECT value, Data.class, size, mean, st FROM Data,
INNER JOIN (
SELECT class, AVG(value) AS mean, STDEV(value) AS st
FROM Data GROUP BY class
) AS stats ON stats.class = Data.class
WHERE value < mean - 2 * st OR value > mean + 2 * st;
This creates a subquery which gets your means and standard deviations for each class, joins those numbers to the rows with matching classes, and then applies your outlier check.

mdx. Filter values from fact table before aggregate

I have the simple cube with 2 dimensions: Dim1, Dim2, and one measure - value (aggregator = sum)
I need to get cross table via mdx:
select non empty [Dim2].members on 0, non empty [Measures].value on 1
from [cube]
=>
el1 el2 el3 el4
value 12 14 45 64
this values is aggregate by dim1. ok.
Next i create calculate measure:
with [Measures].value_filter as iif([Measures].value> 15, [Measures].value, null)
select non empty [Dim2].members on 0,
non empty [Measures].value_filter on 1
from [cube]
=>
we get the correct result:
el3 el4
value 45 64
But, how can i filter cells by non aggregate values of [Measures].value, ie real values from database?
You can only filter by members that are contained in a dimension. If you want to filter on something, it has to be available in the cube. hence you may potentially have to add some columns as attributes to one of your dimensions.
You would do filtering as follows, assuming you want to use Member1 of hierarchy/attribute Hier2 of dimension Dim2 as the filter:
select non empty [Dim2].members on 0,
[Measures].value on 1
from [cube]
where ([Dim2].[Hier2].[Member1])

Can't filter out 1.#INF values

SELECT NON EMPTY {{[Measures].[Net Promoter Score],[Measures].[AvgRevenuePerUnit]}} ON COLUMNS ,
NON EMPTY {{Hierarchize(DrilldownLevel(DrilldownLevel(DrilldownLevel([Employees].[Boss].[ALL]))))}}
ON ROWS
FROM (SELECT ({[Employees].[Boss].&[14404]}) ON COLUMNS
FROM [Enterprise]
WHERE FILTER([Employees].[EID].[EID],[Measures].[Avg Revenue Per Unit] > 700))
WHERE ({[Employees].[Active Status].&[False]},{[Roles].[Roster Role].&[486]},{[Roles].[Enterprise Role].&[2]},
{[Locations].[Location].&[6]},{[Areas].[Area].&[3]},{[Markets].[Market].&[1]},{[Regions].[Region].&[2]},
{[Dates].[Date].&[20130218]:[Dates].[Date].&[20130319]})
When I run above query, AvgRevenuePerUnit column shows 1.#INF. To replace 1.#INF with 0, I used query given below but the result is same. I am using WITH MEMBER in a query given below.
WITH MEMBER [Measures].[AvgRevenuePerUnit] AS (IIF([Measures].[Avg Revenue Per Unit] = '1.#INF', 0, [Measures].[Avg Revenue Per Unit])), Format_String = '0.#0'
SELECT NON EMPTY {{[Measures].[Net Promoter Score],[Measures].[AvgRevenuePerUnit]}} ON COLUMNS ,
NON EMPTY {{Hierarchize(DrilldownLevel(DrilldownLevel(DrilldownLevel([Employees].[Boss].[ALL]))))}}
ON ROWS
FROM (SELECT ({[Employees].[Boss].&[14404]}) ON COLUMNS
FROM [Enterprise] WHERE FILTER([Employees].[EID].[EID],[Measures].[Avg Revenue Per Unit] > 700))
WHERE ({[Employees].[Active Status].&[False]},{[Roles].[Roster Role].&[486]},{[Roles].[Enterprise Role].&[2]},
{[Locations].[Location].&[6]},{[Areas].[Area].&[3]},{[Markets].[Market].&[1]},{[Regions].[Region].&[2]},
{[Dates].[Date].&[20130218]:[Dates].[Date].&[20130319]})
I have a cube provided by user and from that cube I query data. It seems to me that actual value in cube is not 1.#INF that's why it doesn't replace with 0. But what is that value if it is not 1.#INF.
Any solution ?
1.#INF or -1.#INF is how Analysis Services displays plus/minus infinity, which technically/mathematically is the result of dividing something by zero.
The best approach to avoid this is in the definition of the measure, which is probably in the calculation script of the cube. You probably have there something like
CREATE MEMBER CurrentCube.[Measure].[AvgRevenuePerUnit] AS A / B
, VISIBLE = 1;
Replace this with
CREATE MEMBER CurrentCube.[Measure].[AvgRevenuePerUnit] AS IIf(B <> 0, A / B, null)
, VISIBLE = 1;
and you are done. Of course, replace A and B as appropriate.
Note: There was a recent update for Analysis Services 2012 which contains a new MDX function Divide which allows to write
CREATE MEMBER CurrentCube.[Measure].[AvgRevenuePerUnit] AS Divide(A, B)
, VISIBLE = 1;
If you and all other users really have to stick with the definition as it is in the cube, and have to rely on WITH clauses in queries, then I think your code could be written like
WITH MEMBER [Measures].[AvgRevenuePerUnit] AS
IIF([Measures].[Avg Revenue Per Unit] = 1 / 0 -- '1.#INF', plus infinity
OR [Measures].[Avg Revenue Per Unit] = -1 / 0, -- '-1.#INF', minus infinity
0,
[Measures].[Avg Revenue Per Unit]),
Format_String = '0.#0'
...
Your approach of using '1.#INF' does not work, as this is a string, and the infinite numbers are numbers and not strings for Analysis Services.

How can I get MIN and MAX values for dimension members in a set that uses NON EMPTY

I have a problem where I need to get the high and low values for a set from the dimension members (not the measures) for a specific intersection (one customer and time period). We need to reference these for report parameters downstream. I can only find examples for pulling the min and max measures. I need the actual dimension values.
Any ideas?
Assuming the KEY0 is a numerical value, you could do something like :
select
topCount( [Rent Range].[Rent Range Floor].members, 1, [Rent Range].[Rent Range Floor].currentMember.properties( 'KEY0', TYPED ) )
+ bottomCount( [Rent Range].[Rent Range Floor].members, 1, [Rent Range].[Rent Range Floor].currentMember.properties( 'KEY0', TYPED ) )
on 0
from [Sales]
Otherwise any other numerical property would be fine.
I had a similar requirement, see if the following helps you out.
SELECT TOPCOUNT(NONEMPTY(DESCENDANTS([Hit Time].[Date], 1, LEAVES)),1) ON 0
FROM [cube]
For the max you case use TopCount(your set, 1, your measure)
For the min you case use BottomCount(your set, 1, your measure)