With MDX hos to select first row? - mdx

I am using sharepoint report builder.
In my data (se picture below) - I would like to get all the first row - the ones with yellow.
How do i do that.
Here is the MDX code. What should I write to get the yellow rows?
SELECT
NON EMPTY
{[Measures].[Antal unikke brugere - Visiteret Tid]} ON COLUMNS
,NON EMPTY
{
[Borger].[Anonym Borgernøgle DPR].[Anonym Borgernøgle DPR].ALLMEMBERS*
[SundhedOgOmsorg - Ydelse].[Ydelse].[Ydelse].ALLMEMBERS*
[Kalender].[År].[År].ALLMEMBERS*
[Kalender].[Måned].[Måned].ALLMEMBERS
}
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
ON ROWS
FROM
(
SELECT
{
[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.1 Hjemmetrænerforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.2 Komb. Hjemmetræner & Terapeutforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.3 Komplekse Rehabiliteringsforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.7. hverdagsrehab. revis.gr. m. tp.]
} ON COLUMNS
FROM
(
SELECT
{[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]} ON COLUMNS
FROM [FrbLis]
)
)
WHERE
[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]
CELL PROPERTIES
VALUE
,BACK_COLOR
,FORE_COLOR
,FORMATTED_VALUE
,FORMAT_STRING
,FONT_NAME
,FONT_SIZE
,FONT_FLAGS;

You could try using one of the following iterative mdx functions:
Generate - https://msdn.microsoft.com/en-us/library/ms145526.aspx
Filter - https://msdn.microsoft.com/en-us/library/ms146037.aspx
To use filter is a little more convoluted as you need to specify specific tuples based on their relative positions. Generate is a little more straightforward. I will try to provide an example against the MS AdvWrks cube.
I think this is relatively similar to your situation:
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,NON EMPTY
[Product].[Product Categories].[Product]
*
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
} ON 1
FROM [Adventure Works];
You would like the rows I've marked in red (there are lots of products with only 1 row)
So if we now apply the following multi-dimensional expression to the cube:
WITH
SET [prodSet] AS
[Product].[Product Categories].[Product]
SET [prodDtSet] AS
Generate
(
[prodSet] AS P
,Head
(
P.Current
*
NonEmpty
(
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
}
,(
P.Current
,[Measures].[Internet Sales Amount]
)
)
)
)
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,[prodDtSet] ON 1
FROM [Adventure Works];
We get the results required:
Are you able to adapt my example to your context?
I will have a further play and supply a solution using Filter (it'll be, in a way, a little more complicated than the Generate approach)
Here is an approach using Filter:
WITH
SET [prodSet] AS
[Product].[Product Categories].[Product]
SET [prodDtSet] AS
NonEmpty
(
[prodSet]
*
{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20050807]
}
,[Measures].[Internet Sales Amount]
)
SET [prodDtSetFiltered] AS
Filter
(
[prodDtSet]
,
(NOT
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 1).Item(0)
IS
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 2).Item(0))
OR
[prodDtSet].CurrentOrdinal = 1
)
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,[prodDtSetFiltered] ON 1
FROM [Adventure Works];
Results are as following:

Related

MDX: sum over time with range in rows

I have a day level in my time dimension.
I want to output the sum/avg for a selected range of days like in the following statement:
WITH
MEMBER measures.[sum1] AS
Sum([Measures].[Menge_Artikel_Stk])
MEMBER measures.[sum2] AS
Sum
(
[D_Datum].[Datum].[Tag]
,[Measures].[Menge_Artikel_Stk]
)
SELECT
{
[Measures].[stock]
,[Measures].[sum1]
,[Measures].[sum2]
} ON 0
,NON EMPTY
CrossJoin
(
{[D_item].[itemno].[itemno].MEMBERS}
,{
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
}
) ON 1
FROM [Cube];
My goal is to show the sum/avg along the date-dimension filtered on rows.
Instead of 40/1653 i want sum to display 250 for the sum or 35,7 for the average. (1653 is obviously the sum of the entire day level). I want to add this calculated member to an Excel-Sheet. Thus the time range set is variable.
To get the sum/avg rows across the specific range you can do something like this:
WITH
MEMBER measures.[sum1] AS
Sum([Measures].[Menge_Artikel_Stk])
MEMBER measures.[sum2] AS
Sum
(
[D_Datum].[Datum].[Tag]
,[Measures].[Menge_Artikel_Stk]
)
MEMBER [D_Date].[Date].[All].[DaySum] AS
Sum
(
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
)
MEMBER [D_Date].[Date].[All].[DayAvg] AS
Avg
(
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
)
SELECT
{
[Measures].[stock]
,[Measures].[sum1]
,[Measures].[sum2]
} ON 0
,NON EMPTY
CrossJoin
(
{[D_item].[itemno].[itemno].MEMBERS}
,{
{
[D_Date].[Date].[day].[30.01.2017] : [D_Date].[Date].[Day].[05.02.2017]
}
,[D_Date].[Date].[All].[DaySum]
,[D_Date].[Date].[All].[DayAvg]
}
) ON 1
FROM [Cube];
You can use the Axis function to define the current set on your axis:
WITH
MEMBER measures.[sum] AS
Sum(
Axis(1),
[Measures].[Menge_Artikel_Stk]
)
MEMBER measures.[avg] AS
AVG(
Axis(1),
[Measures].[Menge_Artikel_Stk]
)
SELECT
{[Measures].[Menge_Artikel_Stk],[Measures].[sum],[Measures].[avg]} ON 0,
NON EMPTY {[D_Date].[Date].[day].[30.01.2017]:[D_Date].[Date].[Day].[05.02.2017]} ON 1
FROM [Cube];

How to mimic SQL subtraction of results from two different queries in mdx

I wanted to do the trend analysis between the dates. For an instance current date- 30 days
30-60 days and so on.Below is the snippet of comparable sql query but same I wanted to do in MDX.
SQL
SELECT
ROUND
(
(
(
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-30) AND DATE(now())
)
-
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
)
)
/
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
) *100
)
,
0
) AS trend
MDX:
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SELECT
NON EMPTY {[Measures].[CONT_AMT_GROSS], [Measures].[CONT_AMT_NET]} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE [~FILTER]
As of now I have hard coded the dates, that will come from parameters.
I am facing difficulty in creating the second set and how to do subtraction between two sets in MDX.
You already have the logic on how to obtain sets of date corresponding to "last 30 days from now" and "last 60 to last 30 days from now". So, I am going to skip that part.
NOTE - You would have to use the parameter values while building these sets.
What you want to do here is first find the values corresponding to these sets of dates and then perform operations on them.
You can proceed like this -
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SET [Last30Days] AS
...
SET [Last60ToLast30Days] AS
...
MEMBER [~Last30Days - Now] AS
Aggregate
(
[Last30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Last60Days - Last30Days] AS
Aggregate
(
[Last60ToLast30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Measure] AS
([~Last30Days - Now]-[~Last60Days - Last30Days] )/([~Last60Days - Last30Days] * 100), format_string = '#,##0'
SELECT
NON EMPTY {
[Measures].[CONT_AMT_GROSS],
[Measures].[CONT_AMT_NET],
[~Measure]
} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
Format_String takes care of rounding.
Not sure if I totally agree with Sourav's answer as I think some form of aggregation will be needed; creating tuples with sets in them may raise an exception.
Here is a simple model, against AdvWrks, that is tested and will do a subtraction for you:
WITH
SET [Set1] AS
[Date].[Calendar].[Date].&[20060301]
:
[Date].[Calendar].[Date].&[20070308]
SET [Set2] AS
[Date].[Calendar].[Date].&[20070308]
:
[Date].[Calendar].[Date].&[20080315]
MEMBER [Date].[Calendar].[All].[Set1Agg] AS
aggregate([Set1])
MEMBER [Date].[Calendar].[All].[Set2Agg] AS
aggregate([Set2])
MEMBER [Date].[Calendar].[All].[x] AS
(
[Date].[Calendar].[All].[Set1Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[y] AS
(
[Date].[Calendar].[All].[Set2Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[x-y] AS
[Date].[Calendar].[All].[x] - [Date].[Calendar].[All].[y]
SELECT
{
[Date].[Calendar].[All].[x]
,[Date].[Calendar].[All].[y]
,[Date].[Calendar].[All].[x-y]
} ON 0
,[Product].[Category].[Category] ON 1
FROM [Adventure Works];
Reflecting against your code maybe something like the following:
WITH
SET [Set1] AS
[Created_Date.Created_Hir].[Created_On].[2014-04-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-04-30]
SET [Set2] AS
[Created_Date.Created_Hir].[Created_On].[2014-03-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-03-31]
MEMBER [Created_Date.Created_Hir].[All].[Set1Agg] AS
Aggregate([Set1])
MEMBER [Created_Date.Created_Hir].[All].[Set2Agg] AS
Aggregate([Set2])
MEMBER [Measures].[~Last30Days - Now] AS
(
[Created_Date.Created_Hir].[All].[Set1Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Last60Days - Last30Days] AS
(
[Created_Date.Created_Hir].[All].[Set2Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Measure] AS
([Measures].[~Last30Days - Now] - [Measures].[~Last60Days - Last30Days])
/
[Measures].[~Last60Days - Last30Days]
* 100
,format_string = '#,##0'
SET [~ROWS] AS
{
[Sales Order Attributes SO.Sales_order].[Sales Order ID].MEMBERS
}
SELECT
NON EMPTY
{
[Measures].[CONT_AMT_GROSS]
,[Measures].[CONT_AMT_NET]
,[Measures].[~Measure]
} ON COLUMNS
,NON EMPTY
[~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE
[~FILTER];

MDX Multi Level Select

I have
Geography Dimension
-> Admin Hierarchy
-> Province level
-> District level
-> Facility level.
Now I want to find the geography data when province = 'BeiJing' and facility = 'test'. How should I do ?
I write MDX code like this:
SELECT
{} ON 0,
{[Geography.Admin].[BeiJing].[All Geography.Admin].[test]} ON 1
FROM [EIDCube]
but It doesn't work. How can I get all province/district/facility data as table when I set special province and facility ?
In AdvWrks the following throws an error
Query (4, 5) The Customer Geography hierarchy is used more than once
in the Crossjoin function.
This is thrown when I try to run the following:
SELECT
[Measures].[Internet Sales Amount] ON 0
,
[Customer].[Customer Geography].[Country]
*
[Customer].[Customer Geography].[State-Province] ON 1
FROM [Adventure Works];
The way around this is to use the attribute hierarchies which the levels of the [Customer Geography] user hierarchy is made up of, like this:
SELECT
[Measures].[Internet Sales Amount] ON 0
,
[Country].[Country]
*
[State-Province].[State-Province] ON 1
FROM [Adventure Works];
Now if I want Australia and Queensland I can cross-join a couple of single member sets:
SELECT
[Measures].[Internet Sales Amount] ON 0
,
{[Country].[Country].[Australia]}
*
{[State-Province].[State-Province].[Queensland]} ON 1
FROM [Adventure Works];
Results in this:
Edit
Applying the above to your structure you should be able to do something like this:
SELECT
{[Measures].[someMeasureInCube]} ON 0
,
{[Province].[Province].[BeiJing]}
* {[Facility].[Facility].[test]} ON 1
FROM [EIDCube];
Assuming your hierarchichal structure to be
Geography-->Geography.Admin-->Province-->District-->Facility
(dimension) (hierarchy) (level 1) (level 2) (level 3)
Here is the MDX to do it the long way(short way being directly feeding the values in query, which surprisingly didn't work)
select [Geography].[Geography.Admin].CHILDREN
having
[Geography].[Geography.Admin].currentmember.member_caption = "test" and
ancestors([Geography].[Geography.Admin].currentmember, 3).item(0).member_caption = "BeiJing"
on 1,
{} on 0
from EIDCube]
I think you can use this :
SELECT
{} ON 0,
([Geography].[Admin].[BeiJing],[Geography].[Admin].[Province].[District].[test]) ON 1
FROM [EIDCube]
Edit 1 : My previous answer was wrong.
So now I think the better solution is to create a new hierarchy [admin2] for the geography dimension composed of the level [Facility] only and to use this query.
SELECT
{} ON 0,
([Geography].[Admin].[BeiJing],[Geography].[Admin2].[Facility].[test]) ON 1
FROM [EIDCube]

Excluding (All) from sets

I'm using the following but i think there's probably a much simpler method of excluding the All members from the results?
WITH
SET [Non_All_Distributors] AS
{FILTER(
[Distributor Name].members,
(InStr(1, [Distributor Name].CurrentMember.NAME, "All") = 0)
)}
SET [Non_All_Countries] AS
{FILTER(
[Geography Country].members,
(InStr(1, [Geography Country].CurrentMember.NAME, "All") = 0)
)}
SELECT
NON EMPTY
[Dimension].[Hierarchy].DEFAULTMEMBER
ON COLUMNS,
NON EMPTY
[Non_All_Distributors]
*
[Non_All_Countries]
*
Tail([Date].[Date - Calendar Month].[Calendar Day].Members,60)
*
{
[Measures].[Revenue],
[Measures].[NumClients]
}
ON ROWS
FROM [OURCUBE]
Just use
SELECT
NON EMPTY
[Dimension].[Hierarchy].DEFAULTMEMBER
ON COLUMNS,
NON EMPTY
[dimension of Distributor Name].[Distributor Name].[Distributor Name].Members
*
[dimension of Geography Country].[Geography Country].[Geography Country].Members
*
Tail([Date].[Date - Calendar Month].[Calendar Day].Members,60)
*
{
[Measures].[Revenue],
[Measures].[NumClients]
}
ON ROWS
FROM [OURCUBE]
There is no need to define sets here. you can directly state the distributor and country members in the rows clause.
By repeating the attribute name, you restrict the attribute hierarchy - which you refer to by [dim].[attrib name] to the level below the All member, which happens to have the same name as the attribute again. An attribute hierarchy has two levels: level 0 contains the 'All' member and level 1 all the members of the attribute. (This is true only if you did not do special configurations like setting the attribute as non aggregateabable, but I assume the standard case, as you have All members in your hierarchies.
Apart from being more simple, this statement will run much faster, as Filter is a real performance killer in many cases.
I would use the Descendants function and the AFTER option as following; this way you get all the members of the hierarchy below the all member:
select
[Measures].[Amount] on 0,
Descendants([Customers].[Geography].[All], 1, AFTER ) on 1
from [Sales]
(edited: with a request working with MSAS Adv. Works : removed the distance param)
select
Measures].[Order Count] on 0,
Descendants( [Geography].[Geography].[All], , AFTER ) on 1
from [Adventure Works]

Running total only covering range of cells with data

Using the illustrated mockup
(Note not all DimB members show so the total for DimA is larger than the sum of the displayed DimB, ignore this):
Query is showing (months,revenue) on 0, (dima,dimb) on 1 from cube
I would like some assistance in creating the calculated member that would calculate the running total across "Months" here (not a real time dimension).
Earlier i was using this one, but it was wrong on so many levels:
[Measures].[Accumulated Revenue] =
IIF(
([DimMonths].[Months].CurrentMember,[Measures].[Revenue]) = 0
AND ([DimMonths].[Months].CurrentMember.NextMember,[Measures].[Revenue]) = 0
,
IIF(
AGGREGATE({
[DimMonths].[Months].CurrentMember :
[DimMonths].[Months].Parent.LastChild
},[Measures].[Revenue]) = 0
,
NULL
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember.PrevMember
}
,[Measures].[Revenue])
)
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember
}
,[Measures].[Revenue])
)
Sounds like a job for a "scoped assignment". Basically, using a scoped assignment, you can overwrite the value of your calculated measure along the [Member_DimA_01] slice so that these values represent a running total instead of a sum of children.
Here's a good tutorial from Chris Webb on scoped assignments to help get you started...
Edit: here's a template for the running total calculation...
WITH
SET [Months] AS
{
[Date].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Month].&[2011 - Dec]
}
MEMBER [Measures].[Running Total] AS
SUM(
{
[Date].[Calendar Hierarchy].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Hierarchy].CurrentMember
}
,[Measures].[Revenue]
)
SELECT
NON EMPTY{
[Months]
} ON 0,
NON EMPTY{
[DimA].[Member].Allmembers *
[DimB].[Member].Allmembers
} ON 1
FROM
[<<cube name>>]
WHERE
[Measures].[Revenue Running Total]