How can I merge two members into one in a query? - mdx

On rows, I basically want to select all the members of a hierarchy but would like to combine two of them into one. For example, the members would include A, B, and C, so selecting [Group].[Group].members would give me All, A, B, and C but I would like to get All, A,andB&C, where B and C have been merged into one member.
Is this possible within a query?
The database I'm using stores information about the shipping speed of orders, being small parcel, less than truck load, and white glove. I would like to merge small parcel and and less than truck load so I can get aggregate data across the two shipping speeds.
I tried creating a calculate member: [Measures].[Not White Glove] as AGGREGATE([Order Product].[Ships Via Group].&[Small Parcel], [Order Product].[Ships Via Group].&[Less than Truck Load]) but am unsure how to then use that as I currently have [Order Product].[Ships Via Group].members ON ROWS.
When I put ([Measures].[Not White Glove], [Order Product].[Ships Via Group].&[White Glove], [Order Product].[Ships Via Group].&[All]) ON ROWS I get the error Query (14, 11) The Ships Via Group hierarchy is used more than once in the Crossjoin function.
Is there a better way to go about this/what does that error mean?

The error you're seeing is because of your syntax with the parentheses: (a, b, c) defines a tuple where a, b, and c are each members from a different dimension. If you're trying to union these members together, you should use the shorthand: {a, b, c}.
Now, to combine the members is possible, although maybe not as clean and easy as you would want. Here's an example of one way to do it, by creating a new member and then excluding (via Except) the original members from the hierarchy.
WITH
SET [Combined] AS {
[Customer].[Customer Geography].[Country].&[France],
[Customer].[Customer Geography].[Country].&[Germany]
}
MEMBER [Customer].[Customer Geography].[France & Germany] AS Aggregate([Combined])
SELECT
[Measures].[Internet Sales Amount] ON 0,
Union(
Except([Customer].[Customer Geography].[Country], [Combined]),
[Customer].[Customer Geography].[France & Germany]
) ON 1
FROM [Adventure Works]
Results:
Internet Sales Amount
Australia $9,061,000.58
Canada $1,977,844.86
United Kingdom $3,391,712.21
United States $9,389,789.51
France & Germany $5,538,330.05
Hope that helps set you on the right track.

Related

MDX - Top N elements of every subgroup

Let's assume I have a cube with a sales fact table and 3 dimensions: Time (with hierarchy year-month-day), Geography (with hierarchy continent-country-region) and Product with some characteristics about the product sold, let's take the brand for instance.
What I am trying to do is to display the top N brands with respect to the measure chosen, in this case average sales (which is already in the cube as total sales/number of products sold), for every region and month.
I also need to display the country and the year, for clearness.
I have searched for the solution to this everywhere, I came close to it but not completely. I hope someone can help me figure it out.
So I used generate and topcount with the following query, but the problem is that the topcount calculates the N best selling brands over the whole dataset, not for every region and month subgroup. And then applies this top N to every subgroup.
WITH SET [Top N Brands] AS
Generate([Geography].[Region].Children,
TopCount(Geography].[Region].CurrentMember * [Gpu Product].[Brand].[Brand].MEMBERS,
5, ([Measures].[averageSales])))
SELECT {[Measures].[averageSales]} ON COLUMNS,
NON EMPTY ( [Time].[Year].[Year],
[Time].[Month].[Month],
[Geography].[Country].[Country],
[Top N Brands]) ON ROWS
FROM [Cube]
So I am getting this, with the global top 5 brands distributed over the regions, if sold there:
But I should get this with different top 5s for every region:
What am I missing?
You need to use rank. Take a look at the example below. I am using the sample Adventure Works Db, here I am listing For each country, for each product category in that country, the top three subcategories according to internet sales.
WITH
MEMBER [Measures].[Internet Sales Amount Rank] AS
RANK( ([Customer].[Country].currentmember,[Product].[Category].currentmember,[Product].[Subcategory].CurrentMember),
ORDER( ([Customer].[Country].currentmember,[Product].[Category].currentmember,[Product].[Subcategory].[Subcategory].Members) , [Measures].[Internet Sales Amount], BDESC)
)
select
non empty
([Measures].[Internet Sales Amount])
on columns
,
non empty
([Customer].[Country].[Country],
[Product].[Category].[Category],
filter([Product].[Subcategory].[Subcategory],[Measures].[Internet Sales Amount Rank]<4))
on rows
from [Adventure Works]
Result

conditional grouping of dimension members

I struggling with conditional grouping of some members within query.
In my simplified example I have two dimensions and one measure. The first dimension contains some categories and the second dimension some units. In all but one category, all categories have a single unit (category A and B in the example). However, one category has multiple units. If I put both dimensions on rows I get multiple results for category C (as in the following example). What I really need is to get one line per category, with the Amount appropriately aggregated but also with the displayed units (in case of category C, they should be replaced either by single "none" or concatenated together if this is not possible ("km, kg" in the example)).
The following example should illustrate what I am trying to achieve.
With the following query:
SELECT
NON EMPTY { [Measures].[Amount] } ON COLUMNS,
NON EMPTY { ([Grouping A].[Category].[Category].ALLMEMBERS *
[Grouping B].[Unit].[Unit].ALLMEMBERS ) } ON ROWS
FROM [ExampleCube]
I get data like this:
Category Unit Amount
A km 10
B km 5
C km 5
C kg 2
C km 5
But what I really need to achieve is to group the dimension Category and treat the dimension Unit and measure Amount appropriately as follows:
Category Unit Amount
A km 10
B km 5
C none 12
Maybe this is really simple but I have been trying to solve this for a while with no results.
Any ideas would be appreciated.
Thanks.
It's not simple. OLAP hasn't been designed for this kind of things.
Nonetheless, you can solve it in the following way:
With
[Measures].[Unit] as
IIF(
NonEmpty(
[Grouping B].[Unit].[Unit].Members,
[Measures].[Amount]
).Count > 1,
"None",
NonEmpty(
[Grouping B].[Unit].[Unit].Members,
[Measures].[Amount]
).Item(0).Name
)
Select
Non Empty { [Measures].[Unit],[Measures].[Amount] } on 0,
Non Empty { [Grouping A].[Category].[Category].Members } on 1
From [ExampleCube]

MDX combining hierarchy

I'm trying to combine multiple members from a single hierarchy, though this leads to the following error:
Query (11, 3) The Jr-Kw-Mnd-Dag hierarchy is used more than once in the Crossjoin function.
This is a basic version of the Query I'm using:
SELECT
NON EMPTY {
[Measures].[Amount]
} ON COLUMNS
, NON EMPTY {
[Realisatiedatum].[Jr-Kw-Mnd-Dag].[Jaar]
* [Realisatiedatum].[Jr-Kw-Mnd-Dag].[Maand])
} ON ROWS
FROM
[Cube]
Jaar equals year in English, Maand equals month in English. This is what I'm trying to accomplish:
...
november 2013
december 2013
januari 2014
februari 2014
...
Last but not least, the hierarchy:
I would normally create several hierarchies within the Date dimension, such as Calendar, Financial and others that contain just financial year, calendar year, quarters etc.
If you have another hierarchy that contains the month, you could crossjoin with the year of the hierarchy you are using at the moment; then you won't be using the same hierarchy twice in the crossjoin function.
E.g.
, NON EMPTY {
( [Date Dimension].[Financial].[Financial Year]
* [Date Dimension].[Calendar].[Month] ) }
If you want to skip some levels in a user hierarchy, the best is to CrossJoin the corresponding attribute hierarchies of the remaining levels.
Here under I use the attribute hierarchy ([Geography].[City].[City], ..) instead of the user hierachy ([Geography].[Geography].[City],..) form the AW cube:
SELECT
[Measures].[Internet Sales Amount] ON 0,
[Geography].[State-Province].[State-Province] * [Geography].[City].[City] ON 1 FROM [Adventure Works]
Philip,
This issue is related to trying to pull multiple levels from the same hierarchy using a crossjoin and indeed you cannot. As mentioned in other replies, a good work around is to pull the columns you need from places other than the same hierarchy. But that works only if the cube design allows for it.
Your specific problem may be related to the tool you are using to develop the query and which levels in the hierarchy it returns.
For example, the following query when executed in SQL Server Management Studio (versions through V12.0.2000.8) returns only the City level of the hierarchy. But when executed from within design mode in the PowerPivot table import wizard it returns all levels in the hierarchy down to the city level including Country, State-Province and City.
select
[Measures].[Internet Order Count] on columns,
non empty [Customer].[Customer Geography].[City] on rows
from [Adventure Works]

SSAS MDX query, Filter rows by sales people

I am learning how to query Cubes using MDX (SQL Server 2012) queries. I have been presented with a challenge. We have a hierarchy of sales people, a stored procedure returns a table with all sales people working under a manager. I have a classic sales cube where FactSales PK is invoice number and invoice line and a dimension for all our Sales people.
How can I filter the invoices where the sales person is in a table ?
Something like this but translated to MDX:
select * from sales where SalesPerson in (select SalesPerson from #salespeople)
The only way I see this could work is by writing the query dynamically and adding each salesperson in a filter, but that is not optimal in my opinion, we can have 200 or 400 people that we want to return sales from.
thanks!
If the dimension containing the sales people contains the hierarchy (who works for whom), you can resolve the challenge without using the stored procedure. Let's say your manager is named "John Doe" and your sales person hierarchy is named [Sales Person].[Sales Person]. Then just use
[Sales Person].[Sales Person].[John Doe].Children
in your query if you want to see sales for the people working directly for John, and you are done. In case you want to see John himself and everybody working for him directly or indirectly, you would use the Descendants function as follows:
Descendants([Sales Person].[Sales Person].[John Doe], 0, SELF_AND_AFTER)
This function has many variants, documented here.
In the Microsoft sample Adventure Works cube, where a similar hierarchy is called [Employee].[Employees], you could run the following query:
SELECT {
[Measures].[Reseller Sales Amount]
}
*
[Date].[Calendar].[Calendar Year].Members
ON COLUMNS,
Descendants([Employee].[Employees].[Jean E. Trenary], 0, SELF_AND_AFTER)
ON ROWS
FROM [Adventure Works]
to see the sales of employees working directly or indirectly for "Jean E. Trenary".

Many to many dimension - MDX help needed

I’m pretty new to the many-to-many dimensions but I have a scenario to solve, which raised a couple of questions that I can’t solve myself… So your help would be highly appreciated!
The scenario is:
There is a parent-child Categories dimension which has a recursive Categories hierarchy with NonLeafDataVisible set
There is a regular Products dimension, that slices the fact table
There is a bridge many-to-many ProductCategory table which defines the relation between the two. Important to note is that a product can belong to any level of the categories hierarchy – i.e. a particular category can have both – directly assigned products and sub-categories.
There is a fact Transactions table that holds a FK to the Product that has been sold, as well as a FK to its category. The FK is needed, because
I have all this modeled in BIDS, the dimension usage is set between each of the dimensions and the facts, the many-to-many relation between the Categories and the Transactions table is in place is in place. In other words everything seems kind of OK..
I now need to write an MDX which I would use to create a report that shows something like that:
Lev1 Lev2 Lev3 Prod Count
-A
-AA 6
-AA 2
P6 1
P5 1
-AAA 2
P1 1
P2 1
-AAB 2
P3 1
P4 1
+BB
The following MDX almost returns what I need:
SELECT
[Measures].[SALES Count] ON COLUMNS,
NONEMPTYCROSSJOIN(
DESCENDANTS([Category].[PARENTCATEGORY].[Level 01].MEMBERS),
[Product].[Prod KEY].[Prod KEY].MEMBERS,
[Measures].[Measures].[Bridge Distinct Count],
[Measures].[SALES Count],
2) ON ROWS
FROM [Sales]
The problem that I have is that for each of the non-leaf categories, the cross join returns a valid intersection with each of the products that’s been sold for it + all subcategories. Hence the result set contains way too much redundant data and besides I can’t find a way to filter out the redundancies in the SSRS report itself.
Any idea on how to rewrite the MDX so that it only returns the result set above?
Another problem is that if I create a role-playing Category dimension which I set to slice directly the transactions data, then the numbers that I get when browsing the cube are completely off… It seems as SSAS is doing something during processing (but it’s not the SQL statements it shoots to the OLTP, as those remain exactly the same) that causes the problem, but I’ve no idea what. Any ideas?
Cheers,
Alex
I think I found a solution to the problem, using the following query:
WITH
MEMBER [Measures].[Visible] AS
IsLeaf([DIM Eco Res Category].[PARENTCATEGORY].CurrentMember)
MEMBER [Measures].[CurrentProd] AS
IIF
(
[Measures].[Visible]
,[DIM Eco Res Product].[Prod KEY].CurrentMember.Name
,""
)
SELECT
{
[Measures].[Visible]
,[Measures].[CurrentProd]
,[Measures].[FACT PRODSALES Count]
} ON COLUMNS
,NonEmptyCrossJoin
(
Descendants
(
[DIM Eco Res Product].[Prod KEY].[(All)],
,Leaves
)
,Descendants([DIM Eco Res Category].[PARENTCATEGORY].[(All)])
,[Measures].[FACT PRODSALES Count]
,2
)
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
,PARENT_UNIQUE_NAME
,LEVEL_NUMBER
ON ROWS
FROM [Sales];
In the report then I use the [Measures].[CurrentProd] as a source for the product column and that seems to work fine so far.