I am new to MDX and want to develop SSAS cube and need some help on following scenario :
In the SSAS designer, on the Calculations tab:
I am creating one calculated member called [QualityKPI] for which I am writing MDX expression as below :
IIF([Measures].[Rows Count] <> 0 and [Measures].[Coefficient] <> 0, [Measures].[QualityFinal]/[Measures].[Coefficient],IIF([Measures].[Rows Count] <> 0 and [Measures].[Coefficient] = 0,[Measures].[Quality]/[Measures].[NumberofRecords],Null))
But how do I implement here WHERE condition ?
For ex., in my fact table I have a column [Rows Count] with two distinct values of 1 and 0.
I want to implement above MDX expression such that it only considers Rows Count=1 while doing the above calculation.
As an example I have a some records like below and the QualityKPI for each row should yields this results and the formula return exactly the same:
However on aggregation level (Lets say I want to calculate the QualityKPI for all products), I want to consider only records which their [Rows Count] is equal to 1 and therefore the aggregation should yields 0.5496 ((0.209948793 + 0 + 0 + 0) / (0.209948793 + 0 + 0 + 0.172043011 ))but with above formula it yields 0.18087 ((0 + 0.005869074 + 0 + 0 + 0.209948793 + 0 + 0 + 0) / (0 + 0.005869074 + 0 + 0.805352798 + 0.209948793 + 0 + 0 + 0.172043011 )).
Any help is appreciated.
In MDX, WHERE conditions are normally done on attributes, not on measures. So, the best approach would be to make an attribute from your Row Count column (i. e. making it part of a dimension).
Then, you could either leave your calculation as it is, enabling users to do their own where conditions, i. e. by dragging Row Count either into a filter or to rows o columns to see the breakdown by row count.
If you want to filter in your calculation itself, then to add the row count filter to the calculation, you would use tuples wherever you use just a measure currently, e. g. (assuming the attribute is called [Dim1].[Row Count] in the cube, and hence the member for row count 1 would be [Dim1].[Row Count].&[1]), you would use
([Measures].[Rows Count], [Dim1].[Row Count].&[1]) <> 0
instead of
[Measures].[Rows Count] <> 0
and similar for all the measures mentioned in your expression.
You can also use measures (assuming Row Count is one in your cube) for conditions, but that is more complicated to do in cube design and the MDX you need to write, e. g. you would have to think about aggregation to use, and is also much less efficient and hence results in slower queries.
Related
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.
I have a measure(say XX) for a fact but its aggregation type is sum. Now i want to perform a logical case on that i.e if the value of that measure XX is greater than 0 show one else show 0. If I do this with IIF or Case in cube or in excel using olap pivot table extn , I am getting the dim value (against which I will browse this measure) repeatedly / multiple times.
If I use null instead of 0 in IIF or case , I could get the calue but grand total is not shown properly. Also I want that measure XX to act as normal other measures i.e I should be able to browse it against other dims also.
i used the formula available in olap pivot table extension IIF(xx > 0 , 0, 1) (iif(condition , false_val, true_val)) but it causes repetition of dim so i tried iif(xx>0 , 1, null) but can not browse this against multiple dims (same is with case when then end also).
I also tried OLAP pivot table calculation with count and filter function but this is also not giving me desired results. Other approach tried was creating a calculation in cube itself but this also causes the dim populating repeatedly problem . Please let me know if there is some other approach available.
I want to hide rows in SSRS report having Zero Quantity.
There are following multiple Quantity Columns like Opening Stock, Gross Dispatched,Transfer Out, Qty Sold, Stock Adjustment and Closing Stock etc.
I am doing this task by using following expression:
=IIF(Fields!OpeningStock.Value=0 AND Fields!GrossDispatched.Value=0 AND
Fields!TransferOutToMW.Value=0 AND Fields!TransferOutToDW.Value=0 AND
Fields!TransferOutToOW.Value=0 AND Fields!NetDispatched.Value=0 AND Fields!QtySold.Value=0
AND Fields!StockAdjustment.Value=0 AND Fields!ClosingStock.Value=0,True,False)
But by using this expression in row visibility, report hides all the rows except Totals Row. Even though report should show rows having Quantities of above mentioned columns.
Total values are shown correct.
Note: I set this row visibility expression on Detail Row.
Without using expression result is as following.
For the first 2 rows all the quantities are 0 (ZERO), i want to hide these 2 rows.
How can I fix this problem, or which expression must I use to get required results?
Could you try this out?
=IIF((Fields!OpeningStock.Value=0) AND (Fields!GrossDispatched.Value=0) AND
(Fields!TransferOutToMW.Value=0) AND (Fields!TransferOutToDW.Value=0) AND
(Fields!TransferOutToOW.Value=0) AND (Fields!NetDispatched.Value=0) AND (Fields!QtySold.Value=0)
AND (Fields!StockAdjustment.Value=0) AND (Fields!ClosingStock.Value=0),True,False)
Note: Setting Hidden to False will make the row visible
You don't need an IIF() at all here. The comparisons return true or false anyway.
Also, since this row visibility is on a group row, make sure you use the same aggregate function on the fields as you use in the fields in the row. So if your group row shows sums, then you'd put this in the Hidden property.
=Sum(Fields!OpeningStock.Value) = 0 And
Sum(Fields!GrossDispatched.Value) = 0 And
Sum(Fields!TransferOutToMW.Value) = 0 And
Sum(Fields!TransferOutToDW.Value) = 0 And
Sum(Fields!TransferOutToOW.Value) = 0 And
Sum(Fields!NetDispatched.Value) = 0 And
Sum(Fields!QtySold.Value) = 0 And
Sum(Fields!StockAdjustment.Value) = 0 And
Sum(Fields!ClosingStock.Value) = 0
But with the above version, if one record has value 1 and one has value -1 and all others are zero then sum is also zero and the row could be hidden. If that's not what you want you could write a more complex expression:
=Sum(
IIF(
Fields!OpeningStock.Value=0 AND
Fields!GrossDispatched.Value=0 AND
Fields!TransferOutToMW.Value=0 AND
Fields!TransferOutToDW.Value=0 AND
Fields!TransferOutToOW.Value=0 AND
Fields!NetDispatched.Value=0 AND
Fields!QtySold.Value=0 AND
Fields!StockAdjustment.Value=0 AND
Fields!ClosingStock.Value=0,
0,
1
)
) = 0
This is essentially a fancy way of counting the number of rows in which any field is not zero. If every field is zero for every row in the group then the expression returns true and the row is hidden.
Here is an example that should give you some idea..
=IIF(First(Fields!Gender.Value,"vw_BrgyClearanceNew")="Female" and
(First(Fields!CivilStatus.Value,"vw_BrgyClearanceNew")="Married"),false,true)
I think you have to identify the datasource name or the table name where your data is coming from.
I'm building a cube in MS BIDS. I need to create a calculated measure that returns the weighted-average of the rank value weighted by the number of searches. I want this value to be calculated at any level, no matter what dimensions have been applied to break-down the data.
I am trying to do something like the following:
I have one measure called [Rank Search Product] which I want to apply at the lowest level possible and then sum all values of it
IIf([Measures].[Searches] IS NOT NULL, [Measures].[Rank] * [Measures].[Searches], NULL)
And then my weighted average measure uses this:
IIf([Measures].[Rank Search Product] IS NOT NULL AND SUM([Measures].[Searches]) <> 0,
SUM([Measures].[Rank Search Product]) / SUM([Measures].[Searches]),
NULL)
I'm totally new to writing MDX queries and so this is all very confusing to me. The calculation should be
([Rank][0]*[Searches][0] + [Rank][1]*[Searches][1] + [Rank][2]*[Searches][2] ...)
/ SUM([searches])
I've also tried to follow what is explained in this link http://sqlblog.com/blogs/mosha/archive/2005/02/13/performance-of-aggregating-data-from-lower-levels-in-mdx.aspx
Currently loading my data into a pivot table in Excel is return #VALUE! for all calculations of my custom measures.
Please halp!
First of all, you would need an intermediate measure, lets say Rank times Searches, in the cube. The most efficient way to implement this would be to calculate it when processing the measure group. You would extend your fact table by a column e. g. in a view or add a named calculation in the data source view. The SQL expression for this column would be something like Searches * Rank. In the cube definition, you would set the aggregation function of this measure to Sum and make it invisible. Then just define your weighted average as
[Measures].[Rank times Searches] / [Measures].[Searches]
or, to avoid irritating results for zero/null values of searches:
IIf([Measures].[Searches] <> 0, [Measures].[Rank times Searches] / [Measures].[Searches], NULL)
Since Analysis Services 2012 SP1, you can abbreviate the latter to
Divide([Measures].[Rank times Searches], [Measures].[Searches], NULL)
Then the MDX engine will apply everything automatically across all dimensions for you.
In the second expression, the <> 0 test includes a <> null test, as in numerical contexts, NULL is evaluated as zero by MDX - in contrast to SQL.
Finally, as I interpret the link you have in your question, you could leave your measure Rank times Searches on SQL/Data Source View level to be anything, maybe just 0 or null, and would then add the following to your calculation script:
({[Measures].[Rank times Searches]}, Leaves()) = [Measures].[Rank] * [Measures].[Searches];
From my point of view, this solution is not as clear as to directly calculate the value as described above. I would also think it could be slower, at least if you use aggregations for some partitions in your cube.
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.