MDX - rewrite a query using scope - scope

I have an MDX query
IIF
(
IsLeaf([PnL].[PnL_A].CurrentMember)
,
[Measures].[PnL - Plan] * [PnL].[Flag 5].CurrentMember.MemberValue
,Sum
(
[PnL].[PnL_A].CurrentMember.Children
,[Measures].[PnL- Plan (signed)]
)
)
What it does:
The whole thing represents profit and loss. Unfortunately, it is constructed in a way that there are two columns: value of a profit or loss, and flag in the other column.
So if the flag ([PnL].[Flag 5]) is set to -1, the value ([Measures].[PnL - Plan]) is a loss, if the flag is a 1 - the value is a profit. I can't change that.
The query finds leaves of the hierarchy (single deepest source of a profit or loss) and multiplies the flag with the value. For non-leaf members it just aggregates it's leaves.
My problem is that it works too slow - I wanted to rewrite this query using SCOPE but I have no idea how.

Since I have absolutely no idea on your cube structure, let's say your member structure is
Pnl-->Pnl_A-->NonLeaf-->Leaf
You could define scope as below -
CREATE MEMBER CurrentCube.[Measures].[ProfitOrLossValue] AS NULL;
//Current member is leaf and Flag5 is 1
SCOPE
(
[Measures].[ProfitOrLossValue],
[PnL].[Flag 5].&[1],
[PnL].[PnL_A].[Leaf].[All].CHILDREN
);
This = [Measures].[PnL - Plan];
END SCOPE;
SCOPE
(
[Measures].[ProfitOrLossValue],
[PnL].[Flag 5].&[-1],
[PnL].[PnL_A].[Leaf].[All].CHILDREN
);
This = ([Measures].[PnL - Plan] * -1);
END SCOPE;
//Current member is non-leaf
SCOPE
(
[Measures].[ProfitOrLossValue],
[PnL].[PnL_A].[NonLeaf].[All].CHILDREN
);
This = Sum
(
[PnL].[PnL_A].CurrentMember.Children,
[Measures].[PnL- Plan (signed)]
);
END SCOPE;
Hope it helps.

Related

Nested subquery in FOR ALL ENTRIES

Consultant sent me this code example, here is something he expects to get
SELECT m1~vbeln_im m1~vbelp_im m1~mblnr smbln
INTO CORRESPONDING FIELDS OF TABLE lt_mseg
FROM mseg AS m1
INNER JOIN mseg AS m2 ON m1~mblnr = m2~smbln
AND m1~mjahr = m2~sjahr
AND m1~zeile = m2~smblp
FOR ALL ENTRIES IN lt_vbfa
WHERE
AND m2~bwart = '102'
AND 0 = ( select SUM( ( CASE
when SHKZG = 'S' THEN 1
when SHKZG = 'H' THEN -1
else 0
END ) *MENGE ) MENGE
into lt_mseg-summ
from mseg
where
VBELN_IM = m1~vbeln_im
and VBELP_IM = m1~vbelp_im
).
The problem is I don't see how that should work in current syntax. I think about deriving internal select and using it as condition to main one, but is there a proper way to write this nested construction?
As i get it, if nested statement = 0, then main query executes. The problem here is the case inside nested statement. Is it even possible in ABAP? And in my opinion this check could be used outside from main SQL query.
Any suggestions are welcome.
the logic that you were given is part of Native/Open SQL and has some shortcomings that you need to be aware of.
the statement you are showing has to be placed between EXEC SQL and ENDEXEC.
the logic is platform dependent.
there is no syntax checking performed between the EXEC and ENDEXEC
the execution of this bypasses the database buffering process, so its slower
To me, I would investigate a better way to capture the data that performs better outside of open/native sql.
If you want to move forward with this type of logic, below are a couple of links which should be helpful. There is an example select using a nested select with a case statement.
Test Program
Example Logic
This is probably what you need, it works at least since ABAP 750.
SELECT vbeln UP TO 100 ROWS
FROM vbfa
INTO TABLE #DATA(lt_vbfa).
DATA(rt_vbeln) = VALUE range_vbeln_va_tab( FOR GROUPS val OF <line> IN lt_vbfa GROUP BY ( low = <line>-vbeln ) WITHOUT MEMBERS ( sign = 'I' option = 'EQ' low = val-low ) ).
SELECT m1~vbeln_im, m1~vbelp_im, m1~mblnr, m2~smbln
INTO TABLE #DATA(lt_mseg)
FROM mseg AS m1
JOIN mseg AS m2
ON m1~mblnr = m2~smbln
AND m1~mjahr = m2~sjahr
AND m1~zeile = m2~smblp
WHERE m2~bwart = '102'
AND m1~vbeln_im IN ( SELECT vbelv FROM vbfa WHERE vbelv IN #rt_vbeln )
GROUP BY m1~vbeln_im, m1~vbelp_im, m1~mblnr, m2~smbln
HAVING SUM( CASE m1~shkzg WHEN 'H' THEN 1 WHEN 'S' THEN -1 ELSE 0 END * m1~menge ) = 0.
Yes, aggregating and FOR ALL ENTRIES is impossible in one SELECT, but you can trick the system with range and subquery. Also you don't need three joins for summarizing reversed docs, your SUM subquery is redundant here.
If you need to select documents not only by delivery number but also by position this will be more complicated for sure.

SSAS How to scope a calculated member measure to a number of specific members?

I'm trying to create a calculated member measure for a subset of a group of locations. All other members should be null. I can limit the scope but then in the client (excel in this case) the measure does not present the grand total ([Group].[Group].[All]).
CREATE MEMBER CURRENTCUBE.[Measures].[Calculated Measure]
AS (
Null
),
FORMAT_STRING = "$#,##0.00;-$#,##0.00",
NON_EMPTY_BEHAVIOR = { [Measures].[Places] }
,VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Locations';
-----------------------------------------------------------------------------------------
SCOPE ({([Group].[Group].&[location 1]),
([Group].[Group].&[location 2]),
([Group].[Group].&[location 3]),
([Group].[Group].&[location 4]),
([Group].[Group].&[location 5])
}, [Measures].[Calculated Measure]);
// Location Calculations
THIS = (
[Measures].[Adjusted Dollars] - [Measures].[Adjusted Dollars by Component] + [Measures].[Adjusted OS Dollars]
);
END SCOPE;
It's as though the [Group].[Group].[All] member is outside of the scope so it won't aggregate the rest of the members. Any help would be appreciated.
Your calculation is applied after all calculations already happened. You can get around this by adding Root([Time]) to the scope, assuming your time dimension is named [Time]. And if you want to aggregate across more dimensions, you would have to add them all to the SCOPE.
In most cases when you have a calculation that you want too do before aggregation it is more easy to define the calculation e. g. in the DSV, e. g. with an expression like
CASE WHEN group_location in(1, 2, 3, 4) THEN
Adjusted_dollars - adjusted_dollars_by_comp + adjusted_os_dollars
ELSE NULL
END
and just make a standard aggregatable measure from it.
I've searched high and low for this answer. After reading the above suggestion, I came up with this:
Calculate the measure in a column in the source view table
(isnull(a,0) - isnull(b,0)) + isnull(c,0) = x
Add the unfiltered calculated column (x) to the dsv
Create a named calculation in the dsv that uses a case statement to filter the original calc measure CASE WHEN location IN ( 1,2,3)THEN xELSE NULLEND
Add the named calculation as measure
I choose to do it this way to capture the measure unfiltered first then, if another filter needs to be added or one needs to be taken off, I can do so without messing with the views again. I just add the new member to filter by to my named calculation case statement. I tried to insert the calculation directly into a named calculation in the dsv that filtered it as well but the calculation produced the incorrect results.

MDX return fiscal PriorMTD date as value

I am trying to create MDX Calculated member which returns prior mtd date.
This is Calculated member I've created:
CREATE MEMBER CURRENTCUBE.[Measures].PriorMTDDate
AS cousin(
[Date].[Fiscal].CurrentMember,
[Date].[Fiscal].CurrentMember.parent.parent.lag(1)
),
VISIBLE = 1 ;
And this is query, but it returns just null:
select {[Measures].[PriorMTDDate]} on 0
from [WH_Cube]
WHERE ( [Date].[Fiscal].[Date].&[2014-09-12T00:00:00] )
Any idea what am I doing wrong?
EDIT: Another example returning null:
WITH MEMBER Measures.x AS
[Date].[Fiscal].CurrentMember
SELECT Measures.x ON 0
FROM [WH_Cube]
WHERE ( [Date].[Fiscal].[Date].&[2014-09-30T00:00:00] )
Does a measure need to be a numeric value?:
CREATE MEMBER CURRENTCUBE.[Measures].PriorMTDDate
AS cousin(
[Date].[Fiscal].CurrentMember,
[Date].[Fiscal].CurrentMember.parent.parent.lag(1)
).MemberValue ,
VISIBLE = 1 ;
.CurrentMember is evaluated at the row level, doesn't look into the slicer. The slicer is a global restriction on the cube, providing a sub-cube domain for your query.
In your query, [Date].[Fiscal].CurrentMember is underfined, as there is nothing on the Rows clause.
Try
select {[Measures].[PriorMTDDate]} on 0,
[Date].[Fiscal].[Date].&[2014-09-12T00:00:00] on 1
from [WH_Cube]

SSAS Cube calculation Scope with criteria

I need your help with a scope definition where the Goal is to create (in this case) a site = "TAI API", that is the aggregation of two other sites
"CPH API" + "US API" where product
in ([Product].[Manufacturing Family].&[BANT],[Product].[Manufacturing Family].&[BZNT],[Product].[Manufacturing Family].&[VANT]))
What I have done is creating the site as follow:
CREATE MEMBER CURRENTCUBE.[Order Company Group].[Parent].[All].[TAI API]
as [Order Company Group].[Parent].&[10440 - API]+[Order Company Group].[Parent].&[10240 - API]
, VISIBLE = 1 ;
Then I would like to define a scope for this site "TAI API", so that it works for any measure, but I am unsure what the next step is... I have tried something like this, but it doesn't work as intended:
SCOPE ([Order Company Group].[Parent].[All].[TAI API] ) ;<br/>
this = ([Measures].??<br/>
,([Product].[Manufacturing Family].&[BANT],[Product].[Manufacturing Family].&[BZNT],[Product].[Manufacturing Family].&[VANT]));<br/><br/>
END SCOPE;
The [Measures].?? is to indicate that I am not sure if this is needed or what to write...
Turns out I can do something like this
CREATE MEMBER CURRENTCUBE.[Order Company Group].[Parent].[All].[TAI API]
as [Order Company Group].[Parent].&[10440 - API]+[Order Company Group].[Parent].&[10240 - API]
, VISIBLE = 1 ;<br/><br/>
SCOPE ([Order Company Group].[Parent].[All].[TAI API]);<br/>
SCOPE([Product].[Manufacturing Family].[Manufacturing Family].members
- [Product].[Manufacturing Family].&[BANT]
- [Product].[Manufacturing Family].&[BZNT]
- [Product].[Manufacturing Family].&[VANT]
);<br/>
this = null;
<br/>
END SCOPE;
<br/><br/>
END SCOPE;
Thanks Thomas
You can use scope w/o any measures references:
At the very beginning (I just used my own DB with sample on standard Year-Month-Day dimension):
CREATE MEMBER CURRENTCUBE.[Create Date].[Create Date].[Month].&[201402].[20140200]
AS null,
VISIBLE = 1 , ASSOCIATED_MEASURE_GROUP = 'Data' ;
And than scope at the end:
SCOPE ([Create Date].[Create Date].[Month].&[201402].[20140200]);
THIS = SUM({[Create Date].[Create Date].[Day].&[20140214],[Create Date].[Create Date].[Day].&[20140228]});
END SCOPE;
This will work even with calculated measures with Descendants (e.g. ...Exists(Descendants([Create Date].[Create Date].[Year].&[2014],[Create Date].[Create Date].[Month],SELF_BEFORE_AFTER)...)
Please see this image. Is it expected result?
If so, you can just set first time NULL to this new member. And that in scope write
SUM([Order Company Group].[Parent].&[10440 - API],[Order Company Group].[Parent].&[10240 - API])
Hope it helps.

MDX Scope overwriting value

I am trying to overwrite the value of the member [Balance to Total] in two attributes using SCOPE. However, when I view the results in Excel they both have a value of 4. Why aren't they showing different values?
SCOPE ([Measures].allmembers);
[Group].[Attribute1].&[Balance to Total] = 2;
[Group].[Attribute2].&[Balance to Total] = 4;
END SCOPE;
I think that the FREEZE function solves my problem.

Resources