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]
Related
I have got a cube with date dimension:
Period
- Year
-- Quarter
--- Month
---- Date
I need to get count of all dates, selected by user (f.e. in Excel). I have tried to use calculated members like:
[Period].[Period].CurrentMember.children.count
It is good when 1 month is selected. In other ways (selected only few dates or Quarter) it returns the count of children of the next level of hierarchy.
Descendants([Period].[Period],[Period].[Period].[Date]).count
Descendants([Period].[Period].CurrentMember,[Period].[Period].[Date]).count
So I tried to use Descendants. The results are good when 1 element on any level is selected. But one you select f.e. 2 month in one Quarter - it gives counts of all elements.
How can I get count of all selected elements on Date level?
I have also tried:
[Period].[Period].[Date].count
[Period].[Period].[Date].CurrentMember.count
COUNT([Period].[Period].[Date])
COUNT([Period].[Period].[Date].CurrentMember)
To work out multiselect in Excel, you can try Dynamic Set technique. Assume your [Period] dimension has [YQMD] hierarchy, then try the following
CREATE DYNAMIC SET SelectedDates AS (
[Period].[YQMD].[Date] )
CREATE MEMBER CURRENTCUBE.[Measures].[SelectedDatasCount] AS (
SelectedDates.count
)
Refer to this SO article and MSDN discussion. Unfortunately, Mosha's article is no longer available.
Caveat - solution with Dynamic Set can hinder query performance.
This is similar to another question I made (MDX - Running Sum over months limited to an interval) but I feel that I was going off track there.
Let me start again.
I have a calculated measure
MEMBER [Measures].[m_active] AS ([Measures].[CardCount], [Operation].[Code].[ACTIVATION])
That I want to filter on a short interval (let's say from 10 January 2016 to 20 August 2017, those are parametrized)
and another calculated measure that i want to filter since the beginning of date dimension (1st January 2010) to the end of last filter (20 August 2017 in this case), this measure is running sum of all the precedent
MEMBER [Measures].[tot_active] AS (
SUM({[Calendar.YMD].[2010].Children}.Item(0):[Calendar.YMD].CurrentMember, ([Measures].[CardCount], [Operation].[Code].[ACTIVATION]))
On the columns I have this calculated dimensions and on the rows I have months (in the small interval range) and another dimension crossjoined
SELECT
{[Measures].[m_active], [Measures].[tot_attive]} ON COLUMNS,
NonEmptyCrossJoin(
{Descendants([Calendar.YMD].[2016].[Gennaio]:[Calendar.YMD].[2017].[Agosto], [Calendar.YMD].[Month])},
{Descendants([CardStatus.Description].[All CardStatus.Descriptions], [CardStatus.Description].[Description])}
) on ROWS
If I put a date range in the WHERE clause the first member is perfect but i ruin the second, how can I make the second member ignore the WHERE clause? Or is there another solution?
Without testing I'm a little bit unsure of the behaviour, but did you try moving the filter from a WHERE clause into a subselect?
Subselects are formed like this:
...
FROM (
SELECT
<date range for filter> ON 0
FROM cubeName
)
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.
I want to create a barchart with a bar for each month and some measure.
But i also want to filter on a range of day which might not completly overlap some of the month.
When that happen I would like the aggregate count for those month to only aggregat over the days that fall in my date range not get the aggregate for the whole month.
Is that possible with MDX and if it is how should the request look like?
Create a second time dimension, using a virtual dimension of the original dimension. Use one dimension in the WHERE and another in the SELECT.
This often happens anyway if some people want 'Business Time' of quarters and periods, and others prefer months. Or if you have a financial year which runs April-April.
You can use subselect. You can find more information on this page and this page:
When a member is specified in the axis clause then that member with
its ascendants and descendants are included in the sub cube space for
the subselect; all non mentioned sibling members, in the axis or
slicer clause, and their descendants are filtered from the subspace.
This way, the space of the outer select has been limited to the
existing members in the axis clause or slicer clause, with their
ascendants and descendants as mentioned before.
Here is an example:
SELECT { [Customer].[Customer Geography].[Country].&[Australia]
, [Customer].[Customer Geography].[Country].&[United States]
} ON 1
, {[Measures].[Internet Sales Amount], [Measures].[Reseller Sales Amount]} ON 0
FROM ( SELECT {[Customer].[Customer Geography].[Country].&[Australia]
, [Customer].[State-Province].&[WA]&[US]} ON 0
FROM [Adventure Works]
)
The result will contain one row for Autralia and another one for the United States. With the subselect, I restricted the value of United Stated to the Washington state.
One way I found to do it with Mondrian is as follow
WITH MEMBER [Measures].[Units Shipped2] AS
SUM
(
{
exists([Store].[Store Country].currentmember.children,{[Store].[USA].[WA],[Store].[USA].[OR]})
},[Measures].[Units Shipped]
)
MEMBER [Measures].[Warehouse Sales2] AS
SUM
(
{
exists([Store].[Store Country].currentmember.children,{[Store].[USA].[WA],[Store].[USA].[OR]})
},[Measures].[Warehouse Sales]
)
SELECT
{[Measures].[Units Shipped2],[Measures].[Warehouse Sales2]} ON 0,
NON EMPTY [Store].[Store Country].Members on 1
FROM [Warehouse]
I am not sure if the filtering will be done in SQL like below and give good performance or be run locally
select Country, sum(unit_shipped)
where state in ('WA','OR' )
group by Country
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].