I have a "Trend" dimension. The hierarchy is, Trend->Week->Day. The fact is linked to the "Day" key. There is no guarantee that measure value will exist for all days in a given week.
When the user wants to see the measure at "Week" level, I need to show only the last empty day value for that Week. I have multiple measures and hence I ain't interested in creating a new calculated measure for each one of them (like How to display the total of a level as the value of its last child in MDX)
Instead, is there any way to create a named set with which I can achieve the functionality as below?
Example
Week Day Measure
1 1 4
1 2 5
2 3 7
2 7 9
3 5 10
Should get at "Week" level as
Week Day Measure
1 2 5
2 7 9
3 5 10
Thanks! :)
If you want to create a calculated member that can be reused for several measures, you can create a utility dimension that will contain a bunch of calculated member only. Dunno how to do that in SSAS (I'm familiar with icCube). Then you can use this hierarchy in your requests to apply the calculated member.
Let's take your example. I've called the utility dimension [Stats]. Its default member is a calculated member returning the value of the current measure. And it contains the [Last Day] calc. member.
WITH MEMBER [Stats].[Stats].[Last Day] AS (
NonEmpty(
Order( [Trend].[Trend].currentMember.children,
[Trend].[Trend].currentMember.properties( 'key', TYPED ),
BDESC
),
[Stats].[Stats].defaultMember
).item(0),
[Stats].[Stats].defaultMember )
SELECT
[Measures].members on 0,
[Trend].[Trend].[Week].members on 1
FROM [your-cube]
WHERE [Stats].[Stats].[Last Month]
You can see the trick with [Last Month] in the slicer that is applied to each [MEasures] of the SELECT. Then its formula is using a NonEmpty of the [Days] (reversed with the order() based on the key - you might need to adjust) for the current [MEasures].
Related
(I hope my title is clear)
I have a MDX statement that results in:
time (months) in the rows
several projects in the columns
The data displayed is an amount (e.g. costs).
Now I would like to compare the project expenditure for each project and see if there are temporal differences. As such I want to get a fictive time axis (start month, month + 1, month + 2, .... month + 60) and for each relative month the expenditure for each project.
I will give a data example to illustrate (attached picture). (consider the green part as the lifetime of the project - you can assume 0 costs during the lifetime and null costs outside the lifetime):
I think I can write a rather complex MDX for this (e.g. use the current period as the start month and add 12 months to it), then for each project lookup the amount in the "current projected period" - "start date of the project". It will be a bit messy though.
Is there an easier way to do this. For example using one or more of icCube's custom Matrix/Vector functions? I would like to use the end result in a widget to graphically display the data.
We're looking for a table like this one :
+----------+-----------------+----------------+
| | Proj1 | Proj2 |
+----------+-----------------+----------------+
| Month 1 | (Month1,Proj1) | (Month1,Proj2) |
| Month 2 | (Month2,Proj1) | (Month2,Proj2) |
| Month 3 | (Month2,Proj1) | (Month3,Proj2) |
+----------+-----------------+----------------+
Where
MonthN is the Nth month from the start of the project
This MonthN changes dynamically on each cell and will depend on the start date of the project. In MDX this is a calculated member that should look like :
MyCalcM AS IIF( [Project].current.isAll, null, ProjectStartDate([Project].current).lag(n) )
where ProjectStartDate is a function that returns the start date of a project. We won't enter how this function is but we can create a cached schema level declared function with a static context so it will be calculated just once.
Now we need to link this calculated measure with a [project date] dimension.
In MDX this can be done with what we call an Utility dimension ( link ). Utility dimensions are dimension that define a transformation, aka calc. member, for each each of his members instead of the clasical slice&dice behavior.
There are different solutions for building this dimension.
One is doing something similar as the historgram defined here, this might be a bit cumbersome as you need to create manually each member.
Another one is creating directly from a fact table the new dimension, [Project Time], that is not linked in the schema to any facts like this one :
Name , addMonths
First Month, 0
Month 2, 1
Month 3, 2
..
Month N, n-1
We have to create a calculated member that binds this dimension to the calc. members using the member key to calculate the lag ( lag(n) -> lag( [Project Time].current.key ) ) . The drawback of this solution is that we need to activate this calculated measure.
hope it helps
I have a SSAS cube with the following dimensions:
Time
DayName <- Hierarchy
Item
Description <- Hierarchy
In the Measures dimension I have a measure for the LostAmount.
I want to query the cube so that I can get the sum of lost amount per week day. The following query works:
select
except(Time.DayName.members, {Time.DayName.[All]}) on 0,
except(Item.Description.members, {Item.Description.All}) on 1
from Cube
But when returning the results the order of columns is not the natural order of week days (i.e. the order of columns is Friday, Monday, Sunday etc).
How can I have the result columns in the natural order of week days i.e. Monday, Tuesday etc.?
If you look at your screenshot, the days in the Time.DayName level are being sorted in natural order: it's the alphabetical order of the member names.
There's no way that SSAS can "know" what the order you want is. I'd suggest adding a Key column to this dimension, numbering the days in the order you want, and changing the dimension attribute's OrderBy property to Key rather than Name. (Perhaps you already do have a key: but OrderBy=Name will naturally order the members by their name).
Addition: There is a dimension attribute Type property in SSAS, which can be set to "Day of Week" - but I've never used it, and don't know whether it would correctly detect that your member names are the names of weekdays. Or whether it will order your week starting on the "right" day that you want to start your week from. You could try setting it and seeing what happens.
While it's definitely better to change the cube structure, sometimes it's not a feasible option. In such cases, it has to be handled inside MDX code(which is slower). Below is one way.
WITH
MEMBER measures.weekdaynumber AS
CASE Time.DayName.CURRENTMEMBER
WHEN "Monday" THEN 1
WHEN "Tuesday" THEN 2
WHEN "Wednesday" THEN 3
WHEN "Thursday" THEN 4
WHEN "Friday" THEN 5
WHEN "Saturday" THEN 6
WHEN "Sunday" THEN 7
END
SELECT
Order
(
Except
(
Time.DayName.MEMBERS
,{Time.DayName.[All]}
)
,Measures.weekdaynumber
) ON 0
,Except
(
[Item].[Description].MEMBERS
,{[Item].[Description].[All]}
) ON 1
FROM [Cube];
I have found a workaround for the ordering issue by defining additional members on the Measures dimension and outputting them in the desired order:
with
member Measures.Monday as
sum(Time.DayName.&[Monday], Measures.LostValue)
member Measures.Tuesday as
sum(Time.DayName.&[Tuesday], Measures.LostValue)
member Measures.Wednesday as
sum(Time.DayName.&[Wednesday], Measures.LostValue)
member Measures.Thursday as
sum(Time.DayName.&[Thursday], Measures.LostValue)
member Measures.Friday as
sum(Time.DayName.&[Friday], Measures.LostValue)
member Measures.Saturday as
sum(Time.DayName.&[Saturday], Measures.LostValue)
member Measures.Sunday as
sum(Time.DayName.&[Sunday], Measures.LostValue)
select
{
Measures.Monday,
Measures.Tuesday,
Measures.Wednesday,
Measures.Thursday,
Measures.Friday,
Measures.Saturday,
Measures.Sunday
} on 0,
except(Item.Description.members, {Item.Description.[All]}) on 1
from [Cube]
I'm currently working with MDX in pentaho.
Currently I'm facing issue is that Unable to get top 10 count based on a Measure.
i.e., I want to write MDX query for find top 10 customer's based on Current year Sales volume and also needed Previous year sales amount for that customers.
My Problem is that MDX query Sum the Previous and Current year sales volume and listed out the top 10.
How can i get top 10 based on Current year column?
For Example,
Customer Current Year Previous Year
A 100 200
B 150 125
C 200 -
Expected Result:
Customer Current Year Previous Year
C 200 -
B 150 125
A 100 200
Please help me out.
The Topcount function takes 3 arguments, a Set, the number of items to return and a numeric expression.
Supposing you have [Customer].Members on Rows, two [Time] dimension members already defined and [Measures].[Sales] as your measure, you can use
Select
TopCount( [Customer].Members, 3, ( [Measures].[Sales], [Time].[Current Year]) ) on Rows,
{ [Time].[Current Year], [Time].[Previous Year] } on Columns
From [My Cube]
Where [Measures].[Sales]
The TopCount will return the top 3 customers, based on their rank by
([Measures].[Sales], [Time].[Current Year])
If you don't specify this tuple as the numeric expression you get the rank by the overall [Measures].[Sales] value.
Documentation: http://technet.microsoft.com/en-us/library/ms144792.aspx
So I have a value that represents the length in days on a fact table. I'd like to create queries that break that value out into N number of bands (say 4 bands) by year. Is there a way to do that with CalculatedMembers? For example, I'd like to have bands for: < 1 year, 1-3 years, 3-5 years, 5+ years. I could do it with days like:
0 - 365
365 - 1095
1096 - 1825
1826 - infinity
Any idea how to do this? I'm using Mondrian. I'd like to calculate it on the fly rather than adding a field and changing ETL scripts, etc.
I have a measure defined that represents the average length in days (displayed as 2.4 years) using the aggregation function. But really I want to define a completely new measure that is a calculated measure on that same column where a function returns which band it belongs in as above, then rolls up how many were in each band.
I'm beginning to suspect I have to do this in ETL and create a new column that places them in a band. This is really a new dimension I suspect (not so much a calculated measure).
I understand from your question that you want to have the bands as categories, which would mean you need them as members of some hierarchy. You can dynamically create members in MDX, but only for existing hierarchies. You did not state one, hence I just assume you have a hierarchy of events for which you want to seed cluster the duration, furthermore I assume the hierarchy containing the dimension key is named [Event].[Event Id]. You also dis not state the name of the "average duration" measure. hence I just assume it is called Duration.
Then you could use the following MDX:
WITH Member [Event].[Event Id].[< 1 year] AS
Aggregate(Filter([Event].[Event Id].[Event Id].Members,
[Measures].[Duration] < 1.0
)
)
Member [Event].[Event Id].[1-3 years] AS
Aggregate(Filter([Event].[Event Id].[Event Id].Members,
[Measures].[Duration] >= 1.0 AND [Measures].[Duration] < 3.0
)
)
Member [Event].[Event Id].[3-5 years] AS
Aggregate(Filter([Event].[Event Id].[Event Id].Members,
[Measures].[Duration] >= 3.0 AND [Measures].[Duration] < 5.0
)
)
Member [Event].[Event Id].[5+ years] AS
Aggregate(Filter([Event].[Event Id].[Event Id].Members,
[Measures].[Duration] >= 5.0
)
)
SELECT ... // whatever you want to see
ON COLUMNS,
{
[Event].[Event Id].[< 1 year],
[Event].[Event Id].[1-3 years],
[Event].[Event Id].[3-5 years],
[Event].[Event Id].[5+ years]
}
ON ROWS
FROM [YourCube]
Add WHERE conditions, other hierarchies to the rows or columns, subselects as you like.
I am not sure if this is really fast, but it solves the question.
I'm having a bit of trouble accomplishing something that I think should be relatively straightforward in MDX. I would like to create a calculated member that provides a sum of one of my measures over the previous two weeks at a given point in time. My time dimension looks like:
TimeId TradingDate Day of Week
-----------------------------------
1000 11/1/2012 Thursday
1001 11/2/2012 Friday
1002 11/5/2012 Monday
1003 11/6/2012 Tuesday
... ...
What makes this particularly difficult is that my Time dimension is not quite complete. The members of my Time dimension only correspond to trading days in the stock market, and not all time. This means that weekends, holidays, or any other day in which the stock market is closed are excluded. This also means the normal methods of traversing time such as LAG or PARALLELPERIOD will not work quite right here. LAG(14), for example, means "14 trading days", which at any given point could represent a variable length of actual time.
Inside my calculated member, I'm attempting to use FILTER in order to get only time members that are within the previous two weeks of the CurrentMember. However, I can't seem to figure out the proper syntax (if there is one) to accomplish this. I imagine it would be something like:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
FILTER(
[Time].[TimeId].Children
, [Time].[TradingDate].MemberValue
>= VBA!DATEADD("ww", -2, [Time].[TradingDate].CurrentMember.MemberValue)
)
, [Price]
)
However, this doesn't quite work. I can't seem to separate the context of the calculated members current iteration from what would be a separate context inside of the FILTER function. In other words, I'm not sure how to say:
"When iterating over the set inside of FILTER, compare the current
member of each iteration against the value of the CurrentMember in
the scope of the calculated member"
Is what I'm trying to accomplish even possible? Is there a different approach I could be taking to accomplish what I'm after?
The result you'll get from a calculated member will depend on the axis of your query. So first, make sure you have [Time].[TradingDate] in your axis.
Second, your [Time].[TradingDate] hierarchy should be ordered by Key (I assume TradingDate is the key).
Now you can use this member definition:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
[Time].[TradingDate].CurrentMember.Lag(14):[Time].[TradingDate].CurrentMember, [Price]
)
You can use set aliases to refer to the outer CurrentMember in the Filter context:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
GENERATE([Time].[TradingDate].CurrentMember AS CurrentDateAlias,
FILTER(
[Time].[TimeId].Children
, [Time].[TradingDate].MemberValue
>= VBA!DATEADD("ww", -2, CurrentDateAlias.Item(0).MemberValue)
)
)
, [Price]
)
GENERATE is used just to define the alias somewhere.