Member with Named set returns always the same value in SSAS - ssas

I'm needing to query a cube as a plain table. Also, i need to use a named set for performance reasons (the query takes 10x if not using the set). The issue is that i'm getting the same value for every row for the Date Time calculated member. BTW, i'm using this member cause i haven't found any way to query a named set 'on columns'.
The query looks like this:
with
set [CurrentDates] as filter([Time].[Date].Members, not isempty([Measures].[Net Sold Units]))
member [Measures].[Date Time] as [CurrentDates].Item(1).Member_Key
select
{
[Measures].[Date Time],
[Measures].[Song Name]
--other calculated members
}
on columns
,
subset
(
{
order
(
except
(
NONEMPTY([Trend Transaction].[Trend Transaction].Members, [Measures].[Net Sold Units]),
[Trend Transaction].[Trend Transaction].[All]
),
[Measures].[Date Time], basc
)
}
,0, 50)
on rows
from Trends
where
(
{[Time].[Date].&[2012-09-01T00:00:00],[Time].[Date].&[2012-09-02T00:00:00]}
)
And the result i'm getting looks like this:
Date Time Song Name
9/1/2012 Where Have You Been
9/1/2012 We Are Young
9/1/2012 Wide Awake (Origionally Performed by Katy Perry) [Karaoke Version]
9/1/2012 Breathing
9/1/2012 So Sophisticated (Originally Performed by Rick Ross) [Karaoke Version]
.
.
.
The dates for the last songs is obviously wrong, should e 9/2/2012
I recognize that i'm kinda SSAS newbie, probably there is something i'm missing here :)
Is there any way to do that i'm needing?
Thanks in advance!

Your calculated : member [Measures].[Date Time] as [CurrentDates].Item(1).Member_Key
will always refer to the second item in your set (remember it is 0 based )
What you want is to use the RANK function: this with the CURRENTMEMBER function brings back the item position in the Set as the set is rendered. e.g. with:
set [CurrentDates] as filter([Time].[Date].Members, not isempty([Measures].[Net Sold Units]))
member MemberRank As 'RANK(Time].[Date].CURRENTMEMBER , CurrentDates)'
member [Measures].[Date Time] as [CurrentDates].Item(MemberRank-1).UNIQUE_NAME

Well, the solution was finally to have the set and the member like this:
set CurrentDates as filter([Time].[Date].[Date], not isempty([Measures].[Net Sold Units]))
member [Measures].[Date Time] as CDATE(NONEMPTY(CurrentDates, [Measures].[Net Sold Units]).Item(0).Member_Key)
The key is to have the named set into the SCOPE, to have it referenced in the member.

Related

How To Get All Items Created or Still Open For A Given Time

I am working with a system were items are created (postDate dimension) and closed (endDate dimension). The endDate column is always populated with the last time the item was seen. An item is considered closed in a certain time if its last seen date is before the date you are querying. Each row in the fact table has the item, postDate, endDate, locationID, and some other dimensions used for aggregations. What I am trying to accomplish is getting all items still active for a given time frame. For example I want to know all items posted in November 2008 or before November 2008 that has not yet closed. In SQL it would look something like:
SELECT C.geoCountyArea,TM.CalendarYear,COUNT(DISTINCT a.itemid)
FROM [dbo].[factTable] a
JOIN dbo.dimDate AS TM
ON TM.DateKey BETWEEN postDate AND endDate
JOIN [dbo].[dim_geography] C
ON A.geographyID=C.geographyID
WHERE C.geoCountyArea = '1204000057'
AND TM.CalendarYear = 2008 AND TM.MonthNumberOfYear = 11
GROUP BY C.geoCountyArea,TM.CalendarYear
ORDER BY C.geoCountyArea,TM.CalendarYear
This returns 27,715 which is expected. Now, in MDX this looks like:
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:[PostDate].[Month Name].&[2008]&[11]} * {[EndDate].[Month Name].&[2008]&[11]:NULL},
[Measures].[Fact_itemCount]
)
SELECT NON EMPTY (
Measures.[itemCount]
) ON 0,
NON EMPTY (
{[PostDate].[Month Name].&[2008]&[11]},
{[Geography].[Geo County Area].&[1204000057]}
)ON 1
FROM [Cube];
This returns 27,717 - which is 2 more than the SQL version that could be due to items with no end Date posted. Now, the complication comes when I want to get more than one explicit time - for example item count for all months in 2008 or item count for all years. I looked up methods to link a given param to another one via roll playing dimensions and came across this link. I altered my script so it looks like:
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
,[PostDate].[Calendar])}
* {LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
, [EndDate].[Calendar]):NULL}
, [Measures].[Fact_itemCount]
)
SELECT {Measures.[jobCount]} ON 0,
NON EMPTY (
{[DATE].[Month Name].&[2008]&[11]},
{[Geography].[Geo County Area].&[1204000057]}
)ON 1
FROM [Cube];
This, however, returns only the items created in November 2008 - value of 14,884. If I add in other months I do get individual counts for each month but, again, these are just the items created in those months.
How do I get the "active" item count for a given month/year/quarter without having do explicitly declare the time values in the AGGREGATE?
Can you use NonEmpty?
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:
NONEMPTY(
[PostDate].[Month Name].MEMBERS //<<AMEND TO EXACT STRUCTURE USED IN YOUR CUBE
,[DATE].[Calendar].CURRENTMEMBER
).ITEM(0).ITEM(0)}
* {NONEMPTY(
[EndDate].[Month Name].MEMBERS //<<AMEND TO EXACT STRUCTURE USED IN YOUR CUBE
,[DATE].[Calendar].CURRENTMEMBER
).ITEM(0).ITEM(0): NULL}
, [Measures].[Fact_itemCount]
)
...
This ended up being the solution that provided valid results (tested against SQL calls against the warehouse tables):
WITH MEMBER Measures.[itemCount] AS
AGGREGATE(
{NULL:LINKMEMBER([Post Date].[Calendar],
[Post Date].[Calendar])}
* {LINKMEMBER([Post Date].[Calendar],
[End Date].[Calendar]):NULL},
[Measures].[Fact_itemCount]
)
SELECT {Measures.[itemCount]} ON 0,
NON EMPTY (
{[Post Date].[Month Name].Children},
{[Geography].[Geo County Area].&[1204000057]}
)
FROM [Cube]
Not that I am doing LINKMEMBER against the post and end dates - not against the global Date measure.

How do I reuse a created member throughout an MDX statement?

I have a bunch of calculated members that I need to create which are referenced off a single date.
Rather than repeating the MDX that gets the date member for which the measure will be based off, is there a way to create the date member at the start, and then reference it throughout so that I don't have to repeat the MDX multiple times? I was thinking something like the below however it returns a NULL:
WITH MEMBER [Date].[Retail].[Closing Date] AS
IIF (
[Date].[Retail].CurrentMember.Level.Name = 'Date',
[Date].[Retail].CurrentMember.PrevMember,
[Date].[Retail].CurrentMember
)
MEMBER [Measures].[Closing New] AS
(
[Date].[Retail].[Closing Date],
[Measures].[On Hand Quantity]
)
SELECT
[Date].[Retail].[Date].Members ON ROWS,
{
[Measures].[On Hand Quantity],
[Measures].[Closing New]
} ON COLUMNS
FROM
Retail
WHERE
[Date].[Retail Year].&[2017]
As above, I want to use the Closing Date member multiple times for various calculations.
To investigate why it is returning null try something like the following to see if it is as you expect:
WITH
MEMBER [Measures].[nm] AS
[Date].[Retail].CurrentMember.Level.Name
SELECT
{
[Measures].[On Hand Quantity],
[Measures].[nm]
} ON 0,
[Date].[Retail].[Date].Members ON 1
FROM Retail
WHERE [Date].[Retail Year].&[2017];
(I also switched the declaration order inside the SELECT clause as it is standard to declare columns, as it is axis 0, first followed by rows)
Why yes, there is!
the pattern I follow here is to create a set of one member then reference the first item of that set.
with set currentDate as
[Date].[Retail].[Date].&[20160725]
then reference it in the remainder of your query as
currentDate.item(0)

Calculated SSAS Member based on multiple dimension attributes

I'm attempting to create a new Calculated Measure that is based on 2 different attributes. I can query the data directly to see that the values are there, but when I create the Calculated Member, it always returns null.
Here is what I have so far:
CREATE MEMBER CURRENTCUBE.[Measures].[Absorption]
AS sum
(
Filter([Expense].MEMBERS, [Expense].[Amount Category] = "OS"
AND ([Expense].[Account Number] >= 51000
AND [Expense].[Account Number] < 52000))
,
[Measures].[Amount - Expense]
),
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Expense';
Ultimately, I need to repeat this same pattern many times. A particular accounting "type" (Absorption, Selling & Marketing, Adminstrative, R&D, etc.) is based on a combination of the Category and a range of Account Numbers.
I've tried several combinations of Sum, Aggregate, Filter, IIF, etc. with no luck, the value is always null.
However, if I don't use Filter and just create a Tuple with 2 values, it does give me the data I'd expect, like this:
CREATE MEMBER CURRENTCUBE.[Measures].[Absorption]
AS sum
(
{( [Expense].[Amount Category].&[OS], [Expense].[Account Number].&[51400] )}
,
[Measures].[Amount - Expense]
),
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Expense';
But, I need to specify multiple account numbers, not just one.
In general, you should only use the FILTER function when you need to filter your fact table based on the value of some measure (for instance, all Sales Orders where Sales Amount > 10.000). It is not intended to filter members based on dimension properties (although it could probably work, but the performance would likely suffer).
If you want to filter by members of one or more dimension attributes, use tuples and sets to express the filtering:
CREATE MEMBER CURRENTCUBE.[Measures].[Absorption]
AS
Sum(
{[Expense].[Account Number].&[51000]:[Expense].[Account Number].&[52000].lag(1)} *
[Expense].[Amount Category].&[OS],
[Measures].[Amount - Expense]
),
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Expense';
Here, I've used the range operator : to construct a set consisting of all [Account Number] members greater than or equal to 51000 and less than 52000. I then cross-join * this set with the relevant [Amount Category] attribute, to get the relevant set of members that I want to sum my measure over.
Note that this only works if you actually have a member with the account number 51000 and 52000 in your Expense dimension (see comments).
An entirely different approach, would be to perform this logic in your ETL process. For example you could have a table of account-number ranges that map to a particular accounting type (Absorption, Selling & Marketing, etc.). You could then add a new attribute to your Expense-dimension, holding the accounting type for each account, and populate it using dynamic SQL and the aforementioned mapping table.
I don't go near cube scripts but do you not need to create some context via the currentmember function and also return some values for correct evaluation against the inequality operators (e.g.>) via the use of say the membervalue function ?
CREATE MEMBER CURRENTCUBE.[Measures].[Absorption]
AS sum
(
[Expense].[Amount Category].&[OS]
*
Filter(
[Expense].[Account Number].MEMBERS,
[Expense].[Account Number].currentmember.membervalue >= 51000
AND
[Expense].[Account Number].currentmember.membervalue < 52000
)
,
[Measures].[Amount - Expense]
),
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Expense';
EDIT
Dan has used the range operator :. Please make sure your hierarchy is ordered correctly and that the members you use with this operator actually exist. If they do not exist then they will be evaluated as null:
Against the AdvWks cube:
SELECT
{} ON 0
,{
[Date].[Calendar].[Month].&[2008]&[4]
:
[Date].[Calendar].[Month].&[2009]&[2]
} ON 1
FROM [Adventure Works];
Returns the following:
If the left hand member does not exist in the cube then it is evaluated as null and therefore open ended on that side:
SELECT
{} ON 0
,{
[Date].[Calendar].[Month].&[2008]&[4]
:
[Date].[Calendar].[Month].&[1066]&[2] //<<year 1066 obviously not in our cube
} ON 1
FROM [Adventure Works];
Returns:

MDX show all sales until now

i have a huge table of cashflows that means there are +int values for income and -int values for outcome.
I have MeasureGroup for Sum the amount of money.
I now want to display not only the sum of money per month but also the sum of all the past time until the current month so like that:
Month MoneyAmount Total
1 20 20
2 -10 10
3 5 15
4 -10 5
So i know for the first part its just like
select [Measures].[Money] on 0,
[Date].[Month].Members on 1
From MyCube
but how can i add the sum column?
i thought about something like SUM( { NULL : [Date].[Month].CurrentMember } , [Measures].[Money] ) but that didnt work as well :(
In MDX, the total is already there. You do not have to do complex calculations to get it.
But it depends on your exact hierarchy structure how the All member is called. If you have a date user hierarchy named [Date].[Date], and it has a month level named [Date].[Date].[Month], then the all member of the hierarchy would probably be called something like [Date].[Date].[All]. If [Month] is an attribute hierarchy of the Date dimension, then the "all member" would probably be called [Date].[Month].[All]. In the latter case, the all member would already be the first member of the set [Date].[Month].Members. As you are asking the question, I am assuming this is not the case, and you are using a user hierarchy. Then you could change your MDX query to
select [Measures].[Money] on 0,
Union([Date].[Month].Members, { [Date].[Date].[All] }) on 1
From MyCube
Please note that you can change the name of the All member in the property settings of a dimension when designing an Analysis Services dimension, hence I cannot know the definitive name without knowing the details of this setting in your cube. So you might have to adapt the name of the all member.
You can find this name out in SQL Server Management Studio in an MDX window as follows: open the hierarchy that you are using, and then open the "Members" node, below which you should find the "All Member". You can drag this into your MDX statement, and the proper name will appear there.
As in a running sum?
You need a calculated measure, like this:
With Member [Measures].[Running Sum] as Sum( ( [Date].[Months].Members.Item(0) : [Date].[Months].CurrentMember ), [Measures].[Money])
Select [Date].[Months].Members on Rows,
{[Measures].[Money], [Measures].[Running Sum] } on Columns
From [MyCube]

How to get current row value in a WITH MEMBER calculation MDX?

I would like to calculate a Measure based on the current row.
Problem is I can't find a way to get the current row in a WITH MEMBER part.
WITH MEMBER [Measures].[Test] AS AVG(
NonEmptyCrossJoin(
FILTER(DESCENDANTS([Exigences].[ENVGR], [Levier], SELF),
[Exigences].CurrentMember.Name = 'Chemicals'),
DESCENDANTS([Organization].[Valeo].[Powertrain Systems], [entity], SELF)),
[Measures].[ProgressLevel])
SELECT {[Measures].[ProgressLevel], [Measures].[Test]} ON COLUMNS,
DESCENDANTS([Exigences].[ENVGR].[ENVGR-01.001], [Levier], SELF) ON
ROWS FROM [Exigences]
Chemicals is currently hard coded. That is for the example.
I would like in place of 'Chemicals' to have the current rows value.
So let's say those are the values rows will return 'Chemicals', 'Pharmacy', 'Test', I would like the [Measures].[Test] calculation to change.
Can MDX do that ? If so how can I get the current value.
I tried [Levier].CurrentMember.Name but I think it's conflicting with the [Exigences].CurrentMember.Name.
Any one has an idea ?
Thank you,
This has been taking a bit of effort but that's the advantage to have a nice gold badge. We're using the MDX Generate function and named sets (myCellSet & 2d example in link) :
Not sure this is going to work for your provider but you can try this one :
WITH MEMBER [Measures].[Test] AS AVG(
NonEmptyCrossJoin(
Generate( {[Exigences].CurrentMember} as MyCellSet,
FILTER(DESCENDANTS([Exigences].[ENVGR], [Levier], SELF),
[Exigences].CurrentMember.Name = MyCellSet.CurrentMember.Name)
)
,
DESCENDANTS([Organization].[Valeo].[Powertrain Systems], [entity], SELF)),
[Measures].[ProgressLevel])