I have a simple SSAS model from a fact table FactPerformance:
- DateKey
- WorkplaceKey
- Measure1
- Measure2
The dimension DimWorkplace consists of a hierachy:
Plant
Department
Area
Workplace
I have to create KPIs where the goals are given by Area and Department. The goals for the Workplace has to be calculated from the Area where it is assigned to. The goals are not aggregateable and have to be configurable in a way like:
Plant = "Plant 1", Department = "Milling": Goal1 = 0.82, Goal3 = 0.85
Plant = "Plant 1", Department = "Milling", Area = "Area A": Goal1 = 0.9, Goal2 = 0.92
Furthermore, the goals might change over time, the values have to be historized (SCD?).
My first idea was to turn the dimension DimWorkplace into a SCD and add the attributes for the goals. For various reasons I would prefer an independet storage for the goals.
I had troubles finding examples for some sample implementations. Are there any best practices? How are those challenges usually solved? Do you have any hints for me? Thanks in advance!
Andreas
One way is to add another fact table "FactPerformanceGoal" with the same dimensions and measures.
Another (prefered) is to add a dimension called "Version" to your fact tabe. The "version" dimension has 2 members. "actual" and "goal". Link all your current rows in the fact to "actual" and then add more rows linked to "goal" for your goals.
Ssas supports a default member for dimensions. Make the "actual" member the default member and set the dimension to "not aggregateable".
Related
I have a hierarchy in a dimension in my cube, and a fact table that references that dimension. Let's call that a hierarchy of departments and the fact table contains billing targets set for each department (on a record-per-day basis if that's of any interest).
The data is aggregated as in a usual hierarchy in a multidimensional cube.
The problem is that the data in the fact table is not just limited to the "leaf" departments in the hierarchy tree, and so each node/department may or may not have an actual value for a billing target.
I need to have my measure returning the actual value for any node if there is a value, or the sum of the values of it's descendants (if they themselves have actual values, then ignore their descendants).
I can return the value at any given node by using the .DATAMEMBER property and add a condition to substitute the null (if that is the case) with the sum of descendants as so:
with member DirectD as (iif(([Department].[Departments].currentmember.datamember, [Measures].[Department Billing Target]) = null,
([Measures].[Department Billing Target]),
([Department].[Departments].currentmember.datamember, [Measures].[Department Billing Target])))
The problem is that I cannot ensure that the same logic applies to every node "down" the hierarchy.
The MembersWithData setting is set to NonLeafDataHidden in the dimension.
[Measures].[Department Billing Target] is a calculated member, so it looks like Aggregate is not an option.
As an example, I'd like to get the value of 3000 if I query the billing target for department A (image 1):
For department C on Image 2 I need to get 1400 (E, while having descendants, has an actual value which takes precedence over the sum of it's children).
Any help would be greatly appreciated.
The Hierarchy that you mention seems to be a parentchild hierarchy since you say "The problem is that the data in the fact table is not just limited to the "leaf" departments in the hierarchy tree". Based on this, the problem is that we need to solve is
1)Foreach member of you hierarchy we call the base attribute.
2)If the measure value for the base attribute is null we retuen the summed up value
3)If the measure value for the base attribute is not null then we retuen the indivisual members value. Below is the code piece, there can be some syntax issues but would explain the idea.
The below code is a similar example on adventure works(I did add FullName attribute in the employee dimension). In the picture on right is a parent child hierarchy's, base attribute. This picture show all the employee who had sales. On the left is the hierarchy, notice how the values change in the Test measure for people who are present on the right hand side. For example take a look at "Amy E. Alberts"
The code is
with member [Measures].test as
case when [Employee].[Employees].currentmember.name='All Employees'
then [Measures].[Reseller Sales Amount]
when (strtomember('[Employee].[Full Name].['+[Employee].[Employees].currentmember.name+']'),[Measures].[Reseller Sales Amount])=null
then [Measures].[Reseller Sales Amount]
else (strtomember('[Employee].[Full Name].['+[Employee].[Employees].currentmember.name+']'),[Measures].[Reseller Sales Amount])
end
select {[Measures].[Reseller Sales Amount],[Measures].test}
on columns,
[Employee].[Employees].members
on rows from [Adventure Works]
In the end, I have added the following solution that is working so far:
IIF(NOT ISEMPTY(([Department].[Departments].CURRENTMEMBER.DATABEMBER, [Measures].[Department Billing Target Canonical])),
([Department].[Departments].CURRENTMEMBER.DATABEMBER, [Measures].[Department Billing Target Canonical]),
IIF(ISEMPTY(SUM(descendants([Department].[Departments].CURRENTMEMBER, [Department].[Departments], AFTER), IIF(
ISEMPTY(([Department].[Departments].CURRENTMEMBER.parent.DATABEMBER, [Measures].[Department Billing Target Canonical])),
([Department].[Departments].CURRENTMEMBER.DATABEMBER, [Measures].[Department Billing Target Canonical]),
NULL))),
([Department].[Departments].CURRENTMEMBER.DATABEMBER, [Measures].[Department Billing Target Canonical]),
SUM(descendants([Department].[Departments].CURRENTMEMBER, [Department].[Departments], AFTER), IIF(
ISEMPTY(([Department].[Departments].CURRENTMEMBER.parent.DATABEMBER, [Measures].[Department Billing Target Canonical])),
([Department].[Departments].CURRENTMEMBER.DATABEMBER, [Measures].[Department Billing Target Canonical]),
NULL))))
Granted it may not be the prettiest solution (in fact I'm pretty sure it's one of the ugliest), but it works for me.
The gist of it is that the algorithm checks if the parent node of the current one has any data (currentmember.parent.datamember) and if so, substitutes the current member's value with NULL. All those values are piled up in a set, and the sum of it's "contents" is the resulting value. The outmost IIF is there to cover a sort of an edge case.
EDIT: There is also a feeling that this whole issue is just a matter of some SSAS setting that has to be changed. This setting continues to elude me.
I have an OLAP Cube in which there is a Parent-Child Account Dimension.
My goal is to set a certain measure value on the GROSS-PROFIT Account , with a certain logic :
GROSS PROFIT = REVENUES - COSTS
GROSS PROFIT is the parent of REVENUES and COSTS in my account hierarchy, and now the measure shows me the sum (obviously) , not the substraction.
The measure is named [Measures].[Report]
I don’t know how to return, in my measure, the substraction only for the GROSS PROFIT Account , so please help me.
Tks a lot
Daniel
I solved the problem , I saw that exists an “operator column” in the dimension definition, that permits to perform some operation like substraction and addition between members only specifying a certain value column (setted for ex to “+” or “-“)
I am trying to replicate the following sql statement into MDX so that I can create a calculated member in the cube using the base loaded members instead of having to calculate it outside the cube in the table and then loading it
SUM(CASE WHEN ((A.SALES_TYPE_CD = 1) AND (A.REG_SALES=0))
THEN A.WIN_SALES
ELSE 0
END) AS Z_SALES
I am currently loading SALES_TYPE_CD as a dimension and REG_SALES and WIN_SALES as measures.
I also have a few other dimensions in the cube but for simplicity, lets just say I have 2 other dimensions, LOCATION and ITEM
The dimension has LOCATION has 3 levels, "Region"->"District"->"Store", ordered from top to bottom level.
The dimension has ITEM has 3 levels, "CLASS"->"SUBCLASS"->"SKU", ordered from top to bottom level.
The dimension has SALES TYPE has 2 levels, "SALES_TYPE_GROUP"->"SALES_TYPE_CD", ordered from top to bottom level.
I know that I cannot create a simple calculated member in the cube which crossjoins the "SALES_TYPE" dimension with another dimension to get the answer I want.
I would think that it would be a more complicated MDX statement something like :
CREATE MEMBER CURRENTCUBE.[Measures].[Z_Sales]
AS 'sum(filter(crossjoin(leaves(), [Sales Type].[Sales Type].
[Sales_Type_CD].&[1]), [Measures].[REG_SALES]=0),[Measures].
[WIN_SALES])',
FORMAT_STRING = '#,#',
VISIBLE = 1 ;
But this does not seem to return the desired result.
What would be the proper MDX code to generate the desired result?
I did a bunch of testing with the data and I now know that there is no way I can get the right answer by using MDX alone in this scenario. Like "Greg" and "Tab" suggested, the only way would be to have reg sales as a dimension. Since this is a measure, that is out of the question because of the large number of possibilities for the value which has a data type of decimal (18,2)
Thanks for taking the time to answer the question.
How can create generic calculated member which i can reuse in order to calculate the statistical deviation on any logical related dimension(s) and measurement ? I need to be able to select any dimension and measure.
I found related discussion here from which i took stdDev function example.
I've created the calculation, but the result it empty.
CREATE MEMBER CURRENTCUBE.[Measures].calcTest
AS iif(IsEmpty(Axis(0).Item(0)), NULL,
StdDev(Axis(1).Item(0).Item(0).Dimension.Children, Axis(0).Item(0))),
FORMAT_STRING = "#,##0.00;-#,##0.00",
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'TestMeasure' ;
If you want to use it for all measures, you would put your calcTest member to another hierarchy not used in the query, maybe an utility hierarchy (see below), and then reference the Measures.CurrentMember instead of Axis(0).Item(0).
To get the calculation generalized for all hierarchies except the measures is hard, as somewhere you have to tell the calculation which hierarchy to use. And to do this in the cube before the query is defined cannot be done. Hence, the approach to use the leftmost hierarchy in the rows (Axis(1).Item(0)) taken in your question can be changed to reference something different in the query, but cannot be completely flexible. Of course, an approach could be to define, say, three similar members, one for the first, one for the second, and one for the third hierarchy in the rows.
For the utility hierarchy, you would create a dimension table with just one row and one column. Let's say the data content of this column in the single row is "-standard-"and reference this single member in all fact tables from an additional foreign key. Then you build the dimension into the cube with the references from all measure groups. Lets say the attribute hierarchy is called [Utility].[Utility]. Make the attribute hierarchy non aggregatable, and set the default member to the "-standard-" member. In the calculation script, you can then add members to this utility dimension like
CREATE MEMBER [Utility].[Utility].StdDevRows1 // StdDev for leftmost hierarchy in the rows
AS StdDev(Axis(1).Item(0).Item(0).Dimension.Children, Measures.CurrentMember),
FORMAT_STRING = "#,##0.00;-#,##0.00",
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'TestMeasure' ;
CREATE MEMBER [Utility].[Utility].StdDevRows2 // StdDev for second hierarchy in the rows
AS StdDev(Axis(1).Item(1).Item(0).Dimension.Children, Measures.CurrentMember),
FORMAT_STRING = "#,##0.00;-#,##0.00",
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'TestMeasure' ;
CREATE MEMBER [Utility].[Utility].StdDevRows3 // StdDev for third hierarchy in the rows
AS StdDev(Axis(1).Item(2).Item(0).Dimension.Children, Measures.CurrentMember),
FORMAT_STRING = "#,##0.00;-#,##0.00",
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'TestMeasure' ;
The advantage of a separate utility hierarchy is that you can combine it with all measures, times, etc., as it is not itself a member of these.
I'm not very experienced in OLAP Cube + MDX, and I'm having a hard time trying to use twice the same measure in a cube.
Let's say that we have 3 Dimensions: D_DATE, D_USER, D_TYPE_OF_SALE_TARGET and 3 tables of Fact: F_SALE, F_MEETING, F_SALE_TARGET
F_SALE is linked to D_USER (who make the sale) and D_DATE (when)
F_SALE_TARGET is linked to D_USER, D_DATE, D_TYPE_OF_SALE_TARGET (meaning: user has to reach various goals/targets for a given month).
I can browse my cube:
Rows = Date * User
Cols = Number of sale, Total amount of sale + the value of 1 target (in the WHERE clause, I filter on [Dim TYPE SALE TARGET].[Code].&[code.numberOfSales])
How can I add other columns for other targets? As all the targets are in the same table, I don't see how to add a second measure from [Measures].[Value - F_SALE_TARGET] linked to a different code, ie. [Dim TYPE SALE TARGET].[Code].&[code.amountOfSale].
your question is not clear to me but it seems like one way to accomplish that is by creating Calculated Members. Basically, select you cube in BIDS, go to the Calculations tab and create Calculated Members. You would be able to insert your MDX query there. For each target type you can create a different calculation such as: ([Measures].[Value - F_SALE_TARGET], [Dim TYPE SALE TARGET].[Code].&[code.amountOfSale])