How to retain expand/collapse with custom MDX in PerformancePoint - mdx

When creating a dashboard in PerformancePoint Services (PPS), I often resort to custom MDX in a number of areas:
Custom Filters
Custom Scorecard Axes
However, in both cases, PPS immediately drops the expand/collapse capability (tree view). I've explored the MDX issued by PPS using SQL Profiler and have attempted to mimic it to no avail.
For example, the following MDX in an MDX filter creates a Year/Month hierarchy without the intermediate semesters and quarters:
SELECT GENERATE(
[Date].[Calendar].[Month].Members
, {
Ancestors([Date].[Calendar].CurrentMember, [Date].[Calendar].[Calendar Year])
, Ancestors([Date].[Calendar].CurrentMember, [Date].[Calendar].[Month])
}
)
DIMENSION PROPERTIES MEMBER_TYPE ON 0
FROM [Adventure Works]
This results in a list of years and month, sorted correctly. But no tree view capabilities remain, despite selecting "Tree View" as the filter view type.
So, how do you feed PPS an MDX result set and end up with a working tree view?

I think instead of using Ancestors just use Descendants.
I usually use this structure in my PPS filters and it gives you tree view:
NonEmpty(
Order(
Descendants(
[Date].[Fiscal Calendar].[All].Children,
[Date].[Fiscal Calendar].[Month],
SELF_AND_BEFORE),
[Date].[Fiscal Calendar].CurrentMember.Member_Key,
DESC)
)
The result is years \ months with data. Descendants is pretty useful. And in a PPS filter expression CurrentMember is out of context. You have no CurrentMember at that point.
Let me know if it's helped or not what you're after.

Related

SSAS - No of Working Days as Named Calculation

I am new to SSAS. I have a requirement, I need to calculate no of working days between user selected date range (either in Excel or SSRS or PowerBI). I found the MDX query, I need assistance with create a named calculation with MDX expression.
Date Dimension (Filtered):
MDX:
WITH MEMBER Measures.WorkingDays AS
COUNT
(
exists( EXISTING {[Dim Date].[Date].[Date].members}
, [Dim Date].[Is Weekday].&[1] )
)
Select {Measures.WorkingDays} on 0 ,
[Dim Date].[Month].[Month] on 1
from [Project Cube]
where ([Dim Date].[Date].&[2018-01-01T00:00:00]:[Dim Date].[Date].&[2018-04-25T00:00:00])
I need to add this named column on Fact table as measurement. I am having trouble with the below items:
Creating named query with MDX expression mentioned.
Adding a [Number of Working Days] as measure in Fact table.
Please correct me, If I am doing it in wrong way. My requirement is I need a [NoOfWorkingDays] as measure in fact table, so that I can use SSAS aggregate to use it as input on other measure, such as ([utilization%] = ([ActualDaysWorked] / [NoofWorkingDays]).
Note that, I can do analysis with the given MDX, but I need to deploy it with precalculated values in cube, so that end user can directly use the cube.
Kindly let me know, if more details required, Thank you.
Welcome to SSAS and MDX. Now to the answer.
I need to add this named column on Fact table as measurement. I am
having trouble with the below items:
Creating named query with MDX expression mentioned. Adding a [Number
of Working Days] as measure in Fact table.
You dont need to add it to the Fact table at all. Open your SSAS project, in your object explorer double click your cube. Now on the top left hand you will see a CALCULATIONS tab. In the CALCULATION tab, Click new calculated member, the icon has a calculator on it.
Please correct me, If I am doing it in wrong way. My requirement is I
need a [NoOfWorkingDays] as measure in fact table, so that I can use
SSAS aggregate to use it as input on other measure, such as
([utilization%] = ([ActualDaysWorked] / [NoofWorkingDays]).
If I remember correctly, the calculated members will not be added into the Aggregations, however the underlying measures would be. Secondly if you are wondering that you can use your calculated Measure in another calculated measure. The answer is yes you can use it in another calculated measure. So this is totally possible
> ([utilization%] = ([ActualDaysWorked] / [NoofWorkingDays])
where [utilization%] and [NoofWorkingDays] are calculated measures.

Calculated Members with multiple Attribute Hierarchy - MDX

I found this little code where it dynamically calculates TOTALs for all Dimension/Hierarchy I want.
This is close to what I need but will not work for Dimensions that have different number of Hierarchy Levels (Attribute Hierarchy). Current Code only works if there is only one Attribute Hierarchy because of CurrentMember.Parent. I could use CurrentMember.Parent.Parent for Dimension.Hierarchy that have two levels and so on but would not work for the the ones with only one Attribute Hierarchy (Level).
CALCULATE;
CREATE MEMBER CURRENTCUBE.[Measures].[Total On Hand Amount]
AS ([Measures].[On Hand Amount],Axis(1).Item(0).Item(0).Dimension.CurrentMember.Parent),
FORMAT_STRING = "#,#",
VISIBLE = 1 ;
I would like to make this MDX code work for any Dimension.Hierarchy regardless of number of Attribute Hierarchy (Level/s).
Any help is appreciated!!
You can use the ancestors function instead of parent. It takes a dimension parameter and a second parameter which shows how many levels you want to get (how deep in the tree to go). So if you know how many levels your dimension has you can use something like:
Ancestors(Axis(1).Item(0).Item(0).Dimension.CurrentMember, 5)
Instead of a number you can also add a dimension level as a second parameter. Then it will go as deep as the dimension level specified - so if you add the root dimension level it should get to there
(Axis(1).Item(0).Item(0).Dimension.Levels(0).Item(0), [Measures].[On Hand Amount])
Above gave me the correct answer, total for a measure for dynamic selection of any dimension but this MDX calculation would not work from PowerBI(DAX) report, which is merely PowerBI's limitation.
I got the TOTAL working now with this -
SCOPE(DESCENDANTS([Warehouses].[Warehouses],,AFTER));
[Measures].[Total On Hand Amount] = (ROOT([Warehouses]),[Measures].[On Hand Amount]);
END SCOPE;
I just have to repeat this SCOPE for each [Dimension].[Hierarchy] in the cube to make the TOTAL work for any selection including multiple dimensions from Power BI. It does not have dynamic functionality like Axis() did, but it yields the result I needed.
Hope this would help someone else too!!

MDX YTD calculated measure

I'm still new to MDX and I'm trying to get some basic functions to work in my SSAS cube. Can you guys point out what I'm doing wrong here? I've added a calculated measure to my cube with the following code:
CREATE MEMBER CURRENTCUBE.[Measures].[Amount YTD]
AS
AGGREGATE(
YTD([OrderDate].[Calendar].CurrentMember)
,[Measures].[Amount]),
VISIBLE = 1, ASSOCIATED_MEASURE_GROUP = 'MyMeasureGroup';
After that I'm trying to get some data going...
SELECT
NON EMPTY
{
[Measures].[Amount]
, [Measures].[Amount YTD]
} ON COLUMNS,
NON EMPTY
{
[OrderDate].[Month].ALLMEMBERS *
[Product].[Product Group].ALLMEMBERS
} ON ROWS
FROM (SELECT ([OrderDate].[Year].&[2014-01-01T00:00:00]:
[OrderDate].[Year].&[2015-01-01T00:00:00]) ON COLUMNS
FROM [SalesOrderIntake])
This is the output I'm getting:
I'm not seeing any errors in my Output messages, which makes it difficult for me to figure out what is acting up. Hoping you guys can help me out on this one.
FYI: the actual select is just for testing purposes. I just want to get that YTD running. I've tried several things and it always comes out empty, so I was hoping to get some actual errors if I would query it directly in SSMS instead of using a BI tool. Also, the OrderDate dimension is a generated Time dimension which was provided to me by VS.
In your query you're using what looks like an attribute hierarchy:
[OrderDate].[Month].ALLMEMBERS
Whereas the measure uses the user hierarchy:
[OrderDate].[Calendar]
If you use Calendar in your script does it work ok?
#Error usually crops up when there are run time errors in MDX code. I could think of one scenario where the error might crop up. You are using [OrderDate].[Calendar].CurrentMember in the calculated member. But if instead of one, there are multiple members from this hierarchy in scope, it will throw an error.
The below is a scenario from Adventure Works.
with member abc as
sum(YTD([Date].[Calendar].currentmember), [Measures].[Internet Sales Amount])
select abc on 0
from [Adventure Works]
where {[Date].[Calendar].[Date].&[20060115], [Date].[Calendar].[Date].&[20060315]}
P.S. Thanks to #whytheq for teaching me this trick of checking this error by double clicking the cell :) Cheers.
I know, its an old post, but in the interest of posterity..
The correct approach is :
Aggregate
(
PeriodsToDate
(
[OrderDate].[Calendar].[Fiscal Year]
,[OrderDate].[Calendar].CurrentMember
)
,[Measures].[Amount]
)

What does an MDX query return?

I just started learning SSAS and cannot understand the basic idea.
What happens when query fixes fewer dimensions than cube has?
All examples usually present queries where intersection of dimensions gives either a point or an axis; in the former case we have the value and in the latter one we get some aggregated value.
Yet I cannot understand what happens when fixed dimensions produce a cube with fewer dimensions. What will be the result of such query?
I'll try to explain it simplier, then the previous answer.
In SELECT statement you define a 'space' more like mathematical space of result. The whole cube is being projected on that space using aggregation functions.
If you want to project part of the cube you use a WHERE clause.
That's the key defference between SQL which was hard for me to grasp in the beginning:)
An MDX query actually returns a cube - well a sub-cube.
I suppose this is enough to show it in action:
SELECT
NON EMPTY
{
[Measures].[Internet Order Count]
} ON COLUMNS
,NON EMPTY
{
[Sales Territory].[Sales Territory].[Country].MEMBERS
*
[Date].[Calendar].[Month].ALLMEMBERS
} ON ROWS
FROM
( //>>>>>>following is a sub-select>>>>>
SELECT
[Date].[Calendar].[Month].&[2008]&[1] ON COLUMNS
FROM [Adventure Works]
);
The section I've marked is a sub-select which returns a cube. That cube is then further queried by the outer script.
If a cube is returned then why do we just see a table of values? Returning a cube and what is actually visible are two different things. All dimensions are used whenever we run an mdx script - if we do not explicitly use the dimension in our script then it is evaluated at the [(All)] level. So even when only a small table is shown by say ssms all the dimensions are being returned by the script and then only certain aspects are being made visible via what is specified in your script.

Dimension hierarchy not showing all data

I have a users dimension, which represents the hierarchy of many shops. For instance, shops are split into Country - > Region -> Town/Village - > Actual Shop. So when you look at it from a hierarchy perspective, it is Level1, Level2, Level3, Level4 etc.
Now the strange thing is, if I execute the MDX query and filtering in the WHERE clause, by the hierarchy, for a specific user no data displays. However, if I execute the same exact MDX not filtering by the hierarchy, but filtering by the attributes, records are shown.
It is important to mention that the user hierarchy [UserIdHierarchy] contains a hierarchy of the following members
[UserLevel1Id]
[UserLevel2Id]
[UserLevel3Id]
[UserLevel4Id]
[UserLevel5Id]
These are the 2 cases, which should return exactly the same results...
Where clause filtering with user hierarchy :
where
(
DESCENDANTS([Dim User].[UserIdHierarchy].&[#12345],0, self)
)
Where clause filtering without user hierarchy :
where
(
DESCENDANTS([Dim User].[UserLevel3Id].&[#12345],0, self)
)
Why don't both of the filters, bring up the same data for this particular user?
The reason was that the User hierarchy was using historical approach. Therefore, when a user had more then one hierarchy (as shown below), for some strange reason the MDX got messed up and stood with the first item in the dimension hierarchy. Below, I am showing 3 different setups of a user, after his registration into the system. To fix my problem, instead of just doing
[Dim User].[UserIdHierarchy].&[#12345]
I'm filtering in the where clause all user members, i.e.
{[Dim User].[UserIdHierarchy].[UserLevel1Id].&[#12345],
[Dim User].[UserIdHierarchy].[UserLevel2Id].&[#12345],
[Dim User].[UserIdHierarchy].[UserLevel3Id].&[#12345]}
Then the actual filtering is done on the FACT data. This way I include all data for all members in the user hierarchy which match my user - which in this case was #12345.