Using the MDX lag and lead functions - ssas

I'm attempting to query an SSAS cube using MDX, I have a list of numeric values which are ordered in the cube and I want to refer to an adjacent cell in the cube in order to return the value.
WITH MEMBER Measures.[LastShift]<br>
AS<br>
(<br>
[Measures].[Impact Value GBP], <br>
[Dim Shift].[Shift Value1].PrevMember<br>
)<br>
MEMBER Measures.[NextShift]<br>
AS<br>
(<br>
[Measures].[Impact Value GBP], <br>
[Dim Shift].[Shift Value1].NextMember<br>
)<br>
SELECT <br>
{NONEMPTY([Measures].[Impact Value GBP]), <br>
Measures.LastShift,<br>
Measures.NextShift<br>
}<br>
ON 0,<br>
NONEMPTY([Dim Shift].[Shift Value1].[Shift Value1])<br>
ON 1<br>
FROM [factTradeValues]<br>
I can see in the RDBMS that I do have adjacent values, but I cannot get the MDX to return anything other than null. Maybe I'm being thick, but cannot see the solution.
Thanks for any help

PrevMember and NextMember are "member functions" so you need do something like this...
WITH
MEMBER Measures.[LastShift] AS
(
[Dim Shift].[Shift Value1].CurrentMember.PrevMember,
[Measures].[Impact Value GBP]
)
MEMBER Measures.[NextShift] AS
(
[Dim Shift].[Shift Value1].CurrentMember.NextMember,
[Measures].[Impact Value GBP]
)

To answer my own question there turned out to be issues with prevmember and nextmember, because I wanted to refer to the next item in turns of the context of my criteria. I actually wanted to refer to the next item in my set, which is subtly different.
In order to refer to an item in a set you use item and then I used rank to get the adjacent cell.
/* Define the shifts appropriate for this scenario */
SET [SpotShifts] AS
EXCEPT(
NONEMPTY([Dim Shift].[Shift Value1].[Shift Value1].MEMBERS,
(
[Dim Shift Entity].[Shift Entity].[GBP/FTSE],
[Dim Date].[Date].[Date].&[20120305],
{PriceImpacts
}
,[Dim Instrument].[Arena Name].[CO/GBP/Lch10/FTSE/140908/Inc_Quarter/5L]
)),[Dim Shift].[Shift Value1].&[0])
MEMBER Measures.CurrentSpotShift
AS
StrToValue([Dim Shift].[Shift Value1].CURRENTMEMBER.NAME)
MEMBER Measures.NextSpotShift AS
IIF((Measures.CurrentSpotShift<0),
SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts)-2).NAME,
SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts)).NAME)
MEMBER Measures.PreviousSpotShift AS
IIF((Measures.CurrentSpotShift<0),
SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts)).NAME,
SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts)-2).NAME)
MEMBER Measures.NextValue AS
IIF(Measures.CurrentSpotShift>0,
([Measures].[Impact Value],SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts))),
([Measures].[Impact Value],SpotShifts.Item(RANK([Dim Shift].[Shift Value1].CURRENTMEMBER,SpotShifts)-2))
SELECT { NONEMPTY([Measures].[Impact Value]),
(Measures.PreviousSpotShift),
(Measures.LastValue),
(Measures.NextSpotShift),
(Measures.NextValue)} ON 0,
NONEMPTY(SpotShifts) ON 1
FROM factTradeCube
I hope this helps somebody as I found the use of rank within item as not an obvious solution to this, but the only one that got me the correct results.

Related

MDX: add a condition to a measure

I would like to modify a measure in order to filter with a set: if the member belongs to the set, the measure returns the default measure, if not it returns 0.
Here is my attempt:
with
MEMBER spename AS [Dim misc].[SpePats].[Speciality Id].[{1037B3B2-EB0C-4DA3-BD9D-EB54F6CA92A5}].FirstChild.membervalue
SET spesSame AS filter([Dim misc].[SpePats].[Speciality Id].MEMBERS
,[Dim misc].[SpePats].CurrentMember.FirstChild.MemberValue = spename)--filter
MEMBER nb AS iif(IsEmpty(Intersect({[Dim misc].[SpePats].CurrentMember}
,spesSame))--intersect
,0
,Measures.[VParcours Nombre])
SELECT {nb} ON 0
,{[Dim misc].[SpePats].[Speciality Id].&[{1037B3B2-EB0C-4DA3-BD9D-EB54F6CA92A5}]
,[Dim misc].[SpePats].[Speciality Id].&[{1095C7D1-F24C-4E22-B2E4-4C2959E29FFD}]} ON 1
FROM [BDD PBM]
Here are some explanations:
First, the name of a characteristic of some hospital services is retrieved. For example, the name can be 'gynecology'.
Then, the set of speciality ids which name is the same as spename is created, hence spesSame is the list of speciality ids whose name is 'gynecology'.
What I need is to construct nb, defined by: if the currentmember of the hierarchy SpePats belongs to spesSame (intersect function), the result is the number of patients, otherwise it is 0, but the result is always the number of patients(in my request, in rows, the first Speciality id belongs to spesSame, not the second one).
thank you.
ok, the syntax of the iif was wrong: the correct one is:
MEMBER nb AS iif(Intersect({[Dim misc].[SpePats].CurrentMember}
,spesSame).count=0--intersect
,0
,[Measures].[VPARCOURS Nombre])
Apparently, isempty tests if the cell is empty. If someone can explains further the reason behind it...

MDX calculation for multiple measures

I have to create the next calculation for 20 different Measures in my OLAP. As you can see the described function calculates the value of a measure the previous year. I have to repeat the code 20 times only changing the specific measure ([Measures].[Sales]) and I think there is a way of changing the specific measure dynamically.
create MEMBER CURRENTCUBE.[Measures].[Sales ant] as
(ParallelPeriod(
[Dim Calendar].[Calendar].[Year]
,1
,[Dim Calendar].[Calendar].CurrentMember
), [Measures].[Sales]),
VISIBLE = 1 ,ASSOCIATED_MEASURE_GROUP = 'Fact Sales';
Is there is a way in MDX to know which measure in the [Measures] group is being used? In this case which is the best way to implement it.
If I remember correctly you can create hidden set of measures like this:
CREATE HIDDEN STATIC SET CURRENTCUBE.[My Set Of Measures] AS
{
[Measures].[Measure 1],
[Measures].[Measure 2],
[Measures].[Measure 3]
};
Then you can create scope assignment for this set:
Scope ([My Set Of Measures]);
this = (ParallelPeriod(
[Dim Calendar].[Calendar].[Year]
,1
,[Dim Calendar].[Calendar].CurrentMember
), Measures.CurrentMember)
End Scope;
Note that instead of concrete measure - [Measures].[Sales] you will reference a measure with Measures.CurrentMember, so when you choose [Measures].[Sales] on your report the scope above will apply.
Hope it will work.

Query to only display matching elements in two dimensions

Short question:
Any idea how I can pull the name from one dimension entry and apply it to another as filter?
Long description: My cube has has dimensions for manufacturer and seller, and I only need sales for "themselves". The dimensions are loaded from distinct tables in the source but have entries with the exact same name.
Manufacturer Seller
A A *
A D
B B *
C C *
C A
C D
A, B and C sell their products themselves, A and C also sell through reseller D. C also sells through A. I'd like to filter for the marked rows only (names matching).
In SQL this would be simple, or the cube might be easily enhanced to flag "own sales", but both options are not available. I need to query the cube "as is".
I tried using STRTOMEMBER and CURRENTMEMBER like so (with NAME and MEMBER_NAME):
STRTOMEMBER("[Dim Seller].[Seller].[" + [Dim Producer].[Producer].CURRENTMEMBER.NAME + "]
That actually works, syntactically, but CURRENTMEMBER seems to always evaluate to ALL and delivers the (correct) measure value for the ALL element yet not the one for matching name.
I also tried to create a WHERE setting the two names equal
[Dim Seller].[Seller].CURRENTMEMBER.NAME = [Dim Producer].[Producer].CURRENTMEMBER.NAME
but that is very SQL and not valid in MDX.
The whole query looks like this:
SELECT
NON EMPTY {
[Measures].[Value]
} ON COLUMNS
, NON EMPTY { (
{
[Dim Producer].[Producer].[A]
, [Dim Producer].[Producer].[B]
, [Dim Producer].[Producer].[C]
}
* [Dim Seller].[Seller].[Seller].ALLMEMBERS
// This line needs to be trimmed to same name as producer
) } ON ROWS
FROM
[Cube]
The producer list is coming from a config file and string-concatenated to the query and subject to change. Having a second seller list to be kept in sync would be a burden but also (when C sells through A) deliver wrong results.
Any idea how I can pull the name from one dimension entry and apply it to another?
The HAVING clause might help you:
SELECT
NON EMPTY {
[Measures].[Value]
} ON COLUMNS
, NON EMPTY {
{
[Dim Producer].[Producer].[A]
, [Dim Producer].[Producer].[B]
, [Dim Producer].[Producer].[C]
}
* [Dim Seller].[Seller].[Seller].ALLMEMBERS
}
HAVING
[Dim Seller].[Seller].CURRENTMEMBER.MEMBER_NAME =
[Dim Producer].[Producer].CURRENTMEMBER.MEMBER_NAME
ON ROWS
FROM
[Cube]
Use the GENERATE function to do the job for you.
with set Producers as
{[Dim Producer].[Producer].[A]
,[Dim Producer].[Producer].[B]
,[Dim Producer].[Producer].[C]}
set Sellers as
[Dim Seller].[Seller].members
//For every producer, get the seller who shares the same name.
set ProducersHavingSameNameAsSellers as
GENERATE(Producers, GENERATE(Sellers, filter
(Sellers,
[Dim Seller].[Seller].CURRENTMEMBER.MEMBER_NAME =
[Dim Producer].[Producer].CURRENTMEMBER.MEMBER_NAME
)
)
)
SELECT
NON EMPTY [Measures].[Value] ON COLUMNS,
ProducersHavingSameNameAsSellers ON ROWS
FROM [Cube]

MDX with snowflaked dimensions

I have an ordinary DimProduct which has a snowflaked DimPriceList where I store for each ProductKey different prices for the products.
In a MDX, depending on certain product properties, I would like to display different prices for the products. The MDX would look something like this.
CASE
WHEN [Dim Product].[Value Group].CurrentMember.MEMBERVALUE = '02' THEN
CASE
WHEN [Dim Product].[Stock Account Nr].CurrentMember.MEMBERVALUE = 101 THEN
([Dim Price List].[Sales1])
WHEN [Dim Product].[Stock Account Nr].CurrentMember.MEMBERVALUE = 102 OR
[Dim Product].[Stock Account Nr].CurrentMember.MEMBERVALUE = 103 THEN
([Dim Price List].[Valuation])
ELSE
0
END
ELSE
1
END
How can I now access the current membervalue of the DimPriceList? I just get 'All' as result and not the actual value for the current member. I've also tried [Dim Price List].[Valuation].CurrentMember.MEMBERVALUE but with no success. Appreciate any sort of help or hints.
You get the [All] member because it IS the default value. In absence of any scope, the engine bases it's calculation around the default member. If you want the output to change based on the current member of Product, you should attempt at creating a calculated member. Encapsulate the logic above into the script which chooses the requisite measure depending upon the current member. I am assuming you must be having Sales1 and Valuation in form of Measure in your cube. If that is the case your calculated member should choose the requisite measure based on the MEMBERVALUE or you can employ
....
[Dim Product].[Stock Account Nr].CurrentMember IS [Dim Product].[Stock Account Nr].&[101]
....clause.
That said, you need to give some scope.

How to indicate the measure when use dimension members as ROWS in mdx query?

Here is the query that I am using:
SELECT
NON EMPTY { [Dim Date].[Week].[Week].Members } ON COLUMNS,
[Dim Source].[Source Name].[Source Name].Members ON ROWS
FROM [Some Cube];
The things is, right now, I have many measures.
But as I am using dimension members on COLUMNS, I cannot indicate the measure anymore.
So this query results in a default measure.
My question is how can I indicate the measure instead of using the default in mdx query?
Or is there any other way that I can do this query (dimension in both row and columns is required for reading result logic in C# in possible) ?
You can do it in two ways:
Either on the SELECT statement, as
{ [Dim Date].[Week].[Week].Members } * { [Measures].[My Measure] } ON COLUMNS,
or on the WHERE slicer by adding
WHERE [Measures].[My Measure]
at the end.