MDX has a nice feature whereby I can specify a range of members:
SELECT ([Canada],[2006]:[2011]) on Rows,
[Measures].members on Columns
FROM [Sales]
Is there a way to calculate the set of even years: {[2006], [2008], [2010]}? I am looking for a way that would work for large sets, so that listing the years manually is not an option.
You can filter you function using a filter function, a declared function and MOD function (MOD returns the remainder from the division - like % in Java ) :
WITH
FUNCTION isEven(Value _number) as Mod( Int(_number) , 2 ) = 0
SELECT
FILTER( [Date].[Date].[Year] as t, isEven( Year( t.current.key) ) ) on 0
FROM [Cube]
If you are using this filter often you could create a FilterEven declared function once in the script (same for isEven() )
Try this. I used adventure works for the query.For the mod logic i took help from
Mod Logic
WITH
MEMBER [Measures].[Data Type] AS
[Date].[Day of Year].CurrentMember.Properties ("Member_Value",TYPED)
MEMBER [Measures].[IsEven] as
[Measures].[Data Type]-Int([Measures].[Data Type]/2)*2
select {[Measures].[Internet Order Count] }
on columns,
filter (
[Date].[Day of Year].[Day of Year],
[Measures].[IsEven]=0)
on rows
from [Adventure Works]
Plus you can have a column in the date dimension have 1,0 to indicate if the year is even or odd. Then simply use that column in the MDX query , no need to do all the above manipulations
Related
I have the following MDX query which computes the Active Opportunities asofdate(defined by greater than start date and less than close date)
This works when the date values are hard coded. But I want it to work with .currentmember which takes the member in the hierarchy and computes the open opportunities between two dates
with member
[Measures].[Cumulative_count_dates]
as
AGGREGATE(
{NULL:[Time Dimension].[Year-Qtr-Month-Date].[Date].&[2011-10-09T00:00:00]} * {[Opportuntity Close Dt].[Year-Qtr-Month-Date].[Date].&[2011-10-11T00:00:00] : NULL}
, [Measures].[Opportunities Count]
)
select {[Measures].[Cumulative_count_dates]} on columns,
NON EMPTY {[Time Dimension].[Year-Qtr-Month-Date].members} on rows
from AdventCube
In other words, I want to pass this as a variable
[Time Dimension].[Year-Qtr-Month-Date].[Date].&[2011-10-09T00:00:00]
Please help.
What's wrong with CurrentMember?
with member
[Measures].[Cumulative_count_dates]
as
AGGREGATE(
{NULL:[Time Dimension].[Year-Qtr-Month-Date].CurrentMember} * {[Opportuntity Close Dt].[Year-Qtr-Month-Date].[Date].&[2011-10-11T00:00:00] : NULL}
, [Measures].[Opportunities Count]
)
select {[Measures].[Cumulative_count_dates]} on columns,
NON EMPTY {[Time Dimension].[Year-Qtr-Month-Date].[Date].members} on rows
from AdventCube
I want to get two plant's oee per month in a specific year (2013), probably it's pretty trivial but I don't know how to do it:
with member [Measures].[OEE] as 'OEE'
select
{
[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT],
[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT2]
} on columns,
{
[Time].[Month]
} on rows
from ExpertPlan
where [Time].[Year].&[2013-01-01T00:00:00]
the select is ok (plants on columns and months on rows), but i'm not sure about the "with" usage to get the values be the [Measures].[OEE]
With is for custom calculated members and custom sets.
Add your measure to the slicer (WHERE clause)
SELECT
{
[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT]
,[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT2]
} ON COLUMNS
,{[Time].[Month]} ON ROWS
FROM ExpertPlan
WHERE
(
[Time].[Year].&[2013-01-01T00:00:00]
,[Measures].[OEE]
);
Here are a couple of prototyped ways of approaching this in AdvWrks cube:
SELECT
[Customer].[Country].&[United States] ON COLUMNS
,[Date].[Calendar].[Month] ON ROWS
FROM [Adventure Works]
WHERE
(
[Date].[Calendar Year].&[2007]
,[Measures].[Internet Sales Amount]
);
SELECT
[Customer].[Country].&[United States] ON COLUMNS
,Descendants
(
[Date].[Calendar].[Calendar Year].&[2007]
,[Date].[Calendar].[Month]
) ON ROWS
FROM [Adventure Works]
WHERE
[Measures].[Internet Sales Amount];
Both of the above result in this result cell set:
Adding on to the other answer, you can also employ a subselect.
SELECT
{
[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT]
,[Equipment].[Plant Hierarchy].[Group].[DEMO_PLANT2]
} ON COLUMNS
,{[Time].[Month]} ON ROWS
FROM
(
SELECT [Time].[Year].&[2013-01-01T00:00:00] ON 0
FROM [ExpertPlan]
)
WHERE
{[Measures].[OEE]}
In MDX, WHERE is the 3rd axis, although it is not too apparent. Think it to be like excel, where you have the rows, columns and values. You can put the hierarchies(attribute) on any of the axes([Measures] also behaves like any regular hierarchy). It will just change the way your final output will look like.
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:
with member [Measures].[BoughtDispenser] as
Sum(Descendants([Customer].[Customer].CurrentMember, [Customer].[Customer]),
Iif(
(IsEmpty(([Item].[ItemNumber].&[011074], [Measures].[Sale Amount]))
And IsEmpty(([Item].[ItemNumber].&[011069], [Measures].[Sale Amount]))
)
Or IsEmpty([Measures].[Sale Amount]),
0 , 1
)
)
select
{[Measures].[Sale Amount]} on columns,
non empty filter([Customer].[Customer].children, [Measures].[BoughtDispenser])
* {[Item].[ItemNumber].members}
on rows
from [Sales]
where [EnteredDate].[Quarter].&[2010-01-01T00:00:00]
;
The object is to show all the items purchased by customers who also bought either of the two dispensers (011069 and 011074).
I based the calculated member on a query I found to do basket analysis. I feel like there should be a way to write it with the set {[Item].[ItemNumber].&[011074], [Item].[ItemNumber].&[011069]} instead of the two IsEmpty tests. Everything I've tried ended up having every Customer in the result.
My environment is SQL Server Analysis Services 2005.
Yes I can! It just required a slightly different approach to the calculated member:
with member [Measures].[BoughtDispenser] as
Sum(Descendants([Customer].[Customer].CurrentMember, [Customer].[Customer])
* {[Item].[ItemNumber].&[011069], [Item].[ItemNumber].&[011074]},
[Measures].[Quantity Shipped]
)
select
{[Measures].[Sale Amount]} on columns,
non empty filter([Customer].[Customer].children, [Measures].[BoughtDispenser])
* {[Item].[ItemNumber].members}
on rows
from [Sales]
where [EnteredDate].[Quarter].&[2010-01-01T00:00:00]
;
Is there a way I limit the values returned by an MDX query in a way similar to a SQL TOP 1 query.
SELECT TOP 1 Names
From tbl_Names
Order by names DESC
e.g. is the a MDX statement that could do the same?
You can use the TOPCOUNT and BOTTOMCOUNT functions. Basically you specify which dimension or set you want the TOP or BOTTOM n from and then specify some measure or numeric expression with which to order the resultset.
Try something like:
From the web..
WITH
SET [TCat] AS
TopCount([Product].[Subcategory].[Subcategory],10,[Measures].[Sales Amount])
MEMBER [Product].[Subcategory].[Other] AS
Aggregate([Product].[Subcategory].[Subcategory] - TCat)
SELECT {
[Measures].[Sales Amount]
} ON COLUMNS,
TCat + [Other] ON ROWS
FROM [Adventure Works]