MDX query just on dimension contents - mdx

Is it possible to write a MDX query that just queries and returns data on a dimension?
For example, assume that I have a 'Sales' cube that has a 'Customer' dimension, and the customer dimension has three properties: 'Customer Name', 'Customer ID' and 'Customer Business Sector'. I want a query that returns the 'Customer Name' and 'Customer ID' properties for all those customers that have a 'Customer Business Sector' value of 'Banking'.

You could use calculated members, something like:
with
member xName as dim.currentMember.NAME
member XProp as dim.currentMember.properties('prop')
select
{ [xName], [xProp] } on 0,
dim.allMembers on 1
from [cube]

Absolutely.
SELECT
NonEmpty
(
Customer.CustomerID.CustomerID.MEMBERS * Customer.CustomerName.CustomerName.MEMBERS,
(Customer.[Customer Business Sector].&[Banking], Mesures.SomeMeasure)
)
ON 1,
{} ON 0
FROM [Sales]

If you're talking about "properties" then maybe the following pattern:
WITH
MEMBER [Measures].[CustName] AS
[Customer].CURRENTMEMBER.properties('Customer Name')
MEMBER [Measures].[CustID] AS
[Customer].CURRENTMEMBER.properties('Customer ID')
MEMBER [Measures].[CustSector] AS
[Customer].CURRENTMEMBER.properties('Customer Business Sector')
SET [CustBankers] AS
FILTER(
[Customer].[Customer].MEMBERS AS C
,[Measures].[CustSector] = 'Banking'
)
SELECT
{
[Measures].[CustName]
,[Measures].[CustID]
} ON 0,
[CustBankers] ON 1
FROM [YourCube];
I suspect then when you mention "property" you're referring to three attribute hierarchies within the Customer dimension. If this is the case then something more like the following:
WITH
MEMBER [Measures].[CustName] AS
[Customer].[Customer Name].CURRENTMEMBER.member_caption
MEMBER [Measures].[CustID] AS
[Customer].[Customer ID].CURRENTMEMBER.member_caption
MEMBER [Measures].[CustSector] AS
[Customer].CURRENTMEMBER.properties('Customer Business Sector')
SET [CustBankers] AS
EXISTS(
[Customer].[Customer].MEMBERS
,[Customer].[Customer Business Sector].[Banking]
)
SELECT
{
[Measures].[CustName]
,[Measures].[CustID]
} ON 0,
[CustBankers] ON 1
FROM [YourCube];

Related

UNION multiple MDX queries in SSAS (powerpivot)

I have some sort of difficulties trying to join 2 MDX queries together. When running them separately they work fine. The script below
WITH
MEMBER [Measures].[ParameterCaption] AS
[Main_Incidents].[Priority].CurrentMember.Member_Caption
MEMBER [Measures].[ParameterValue] AS
[Main_Incidents].[Priority].CurrentMember.UniqueName
MEMBER [Measures].[ParameterLevel] AS
[Main_Incidents].[Priority].CurrentMember.Level.Ordinal
SELECT
{
[Measures].[ParameterCaption]
,[Measures].[# Incidents]
,[Measures].[%SLA]
} ON COLUMNS
,[Main_Incidents].[Priority].ALLMEMBERS ON ROWS
FROM [Model];
WITH
MEMBER [Measures].[ParameterCaption] AS
[Main_Incidents].[usr_directorate].CurrentMember.Member_Caption
MEMBER [Measures].[ParameterValue] AS
[Main_Incidents].[usr_directorate].CurrentMember.UniqueName
MEMBER [Measures].[ParameterLevel] AS
[Main_Incidents].[usr_directorate].CurrentMember.Level.Ordinal
SELECT
{
[Measures].[ParameterCaption]
,[Measures].[# Incidents]
,[Measures].[%SLA]
} ON COLUMNS
,[Main_Incidents].[usr_directorate].ALLMEMBERS ON ROWS
FROM [Model];
The most important bit for me is that I need the label column to show. So I want to UNION the 2 queries together so that the ParameterCaption captures values from "Priority" dimension and "Directorate" dimension....
Please someone help me to achieve this?
This is a bit complex, but definitely possible.
Union in MDX only works for members of the same hierarchy, so to achieve this we need to make the row members into Tuples that combine the two hierarchies. We can do this by cross joining each of the ALLMEMBERS sets to the [All] member for the other hierarchy. Then we just need to change the Parameter Caption, Value and Level to conditionally get the value from the appropriate hierarchy.
This could look something like the code below:
WITH
MEMBER [Measures].[ParameterCaption] AS
IIF([Main_Incidents].[Priority].CurrentMember.Level.Ordinal = 0, [Main_Incidents].[usr_directorate].CurrentMember.Member_Caption, [Main_Incidents].[Priority].CurrentMember.Member_Caption)
MEMBER [Measures].[ParameterValue] AS
IIF([Main_Incidents].[Priority].CurrentMember.Level.Ordinal = 0, [Main_Incidents].[usr_directorate].CurrentMember.UniqueName, [Main_Incidents].[Priority].CurrentMember.UniqueName)
MEMBER [Measures].[ParameterLevel] AS
IIF([Main_Incidents].[Priority].CurrentMember.Level.Ordinal = 0, [Main_Incidents].[usr_directorate].CurrentMember.Level.Ordinal , [Main_Incidents].[Priority].CurrentMember.Level.Ordinal)
SELECT
{
[Measures].[ParameterCaption]
,[Measures].[# Incidents]
,[Measures].[%SLA]
} ON COLUMNS
,{
[Main_Incidents].[Priority].ALLMEMBERS * [Main_Incidents].[usr_directorate].[All],
[Main_Incidents].[Priority].[All] * [Main_Incidents].[usr_directorate].ALLMEMBERS
} ON ROWS
FROM [Model];

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]

MDX query - best salesmen who sold all of given products

Let's say I have two simple dimensions:
Products - with id and name
Salesmen - with id and name
My fact table is named SALES and contains the ids of the abovementioned.
I need to produce a query that will show the names of salesmen who sold all of the given products.
This code solves the problem for two items X and Y:
SELECT
{} on 0,
EXISTS(
EXISTS(
{[Salesmen].[Name].MEMBERS},
{[Products].[Name].&[X]}
)
,{[Products].[Name].&[Y]}
)
ON 1
FROM [Test];
The other version is:
SELECT
{} on 0,
INTERSECT(
NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,([Products].[Name].&[X])
)
,NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,([Products].[Name].&[Y])
)
)
ON 1
FROM [Test];
However, this method becomes troublesome if the list of given products is large, for example - 100 random products..
Do you have a property member_key for the hierarchy [Products].[Name] ? We can test like this:
WITH
MEMBER [Measures].[Meas1] AS
[Products].[Name].CurrentMember.PROPERTIES("KEY ID")
MEMBER [Measures].[Meas2] AS
[Products].[Name].CurrentMember.MEMBER_Key
MEMBER [Measures].[Meas3] AS
[Products].[Name].CurrentMember.MEMBERvalue
select
{
[Measures].[Meas1]
,[Measures].[Meas2]
,[Measures].[Meas3]
} on COLUMNS,
[Products].[Name].MEMBERS on ROWS
FROM [Test];
Hopefully one of the custom measures gives you a value? I'll assume Meas2 is working (swap to a different one if Meas1 or Meas3 is returning numbers)
WITH
MEMBER [Measures].[Meas2] AS
[Products].[Name].CurrentMember.MEMBER_Key
SET [ProdsetA] AS
FILTER(
[Products].[Name].MEMBERS
,[Measures].[Meas2] <100
)
SET [ProdsetB] AS
FILTER(
[Products].[Name].MEMBERS
,[Measures].[Meas2] >500
)
SELECT
{} on 0,
INTERSECT(
NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,[ProdsetA]
)
,NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,[ProdsetB]
)
)
ON 1
FROM [Test];
... the >100 and <500 are important. These are the criteria for the filter function to use. The custom set [ProdsetA] will only contain Products that have MEMBER_Key that are <100 whereas the custom set [ProdsetB] will only contain Products that have MEMBER_Key that are >500. You need to use the member values presented to you by the first script to decide what values 100 and 500 should be in your cube context (...I don't know the key values in your cube so just used 100 and 500 as placeholders)

Adding further information in the context of the cell set

I'd like to be able to search the [Employee Department] hierarchy - within any of it's levels using a string: the following does this ok and finds all members related to the string "Control"
Now I have tried to add a cross join so that I can always see the department name for each of the rows and then ORDER by the department. If the commented section is uncommented I unfortunately get a full cartesian product - I only want the departments in the context of the members found by the filter - is this possible?
WITH
MEMBER [Measures].[LevelName] AS
[Employee].[Employee Department].Level.Name
MEMBER [Measures].[LevelNumber] AS
[Employee].[Employee Department].Level.Ordinal
SET [Set_TargetEmp] AS
{
FILTER(
[Employee Department].AllMembers,
(
InStr(
1,
[Employee].[Employee Department].currentmember.name,
"Control") <> 0
)
)
}
SELECT
// ORDER(
// [Department].members,
// [Department].[Department].MEMBERVALUE
// )
// *
ORDER(
DESCENDANTS(
[Set_TargetEmp],
[Employee].[Employee Department].[Department],
SELF_BEFORE_AFTER
),
[Measures].[LevelNumber],
BASC
) as X
ON 1,
{
[Measures].[LevelName],
[Measures].[LevelNumber]
} ON 0
FROM [Adventure Works]
Assuming you use Department the Department dimension, and the Employee Department is in a different dimension named Employee, you get a cross product. Analysis Services only applies "autoexists" within the same dimension. Across dimensions, you must apply this logic explicitly like this:
ORDER(
Exists([Employee].[Department Name].[Department Name].members,
[Set_TargetEmp]
),
[Department].[Department].MEMBERVALUE
)
for the commented block in your code should deliver what you want.
In case you have more than one measure group that relate to both the department and the employee dimensions, you should state the name of the measure group to use as the third argument of Exists. This is a string argument, hence this name should be included in quotes.

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]