If I run the following some of the resellers are repeated e.g.Sports Products Store - is this as expected?
WITH
SET [InitialSet] AS
EXISTS(
{[Reseller].[Reseller].[Reseller].MEMBERS},
{ [Date].[Calendar Year].&[2007],
[Date].[Calendar Year].&[2008] },
'Reseller Sales'
)
SELECT
{ }
ON 0,
[InitialSet]
ON 1
FROM [Adventure Works]
WHERE (
[Measures].[Reseller Order Quantity]
);
So if I use this set with a measure in the following I get two sets of results for Friendly Bike Shop and also for Sports Products Store:
WITH
SET [InitialSet] AS
EXISTS(
{[Reseller].[Reseller].[Reseller].MEMBERS},
{[Date].[Calendar Year].&[2007],
[Date].[Calendar Year].&[2008]},
'Reseller Sales'
)
SELECT
{
[Date].[Calendar Year].&[2007],
[Date].[Calendar Year].&[2008]
}
ON 0,
ORDER(
[InitialSet]
,([Measures].[Reseller Order Quantity],[Date].[Calendar Year].&[2007])
,BDESC
)
ON 1
FROM [Adventure Works]
WHERE (
[Measures].[Reseller Order Quantity]
);
If you check the details, you will see that e. g. "Friendly Bike Shop" has two different keys: 290 and 643 in the AdventureWorks cube.
And something like this can happen in real life as well: Why would you assume all companies across several countries have different names?
Related
EDITED With RANK/ORDER Suggested changes below:
Currently I'm returning the sum of the Prices for all Suppliers that sell the product.
What I want is to return the Product Name, and Price for the row that has the max highest price for the rows with the same product for each product.
Code:
--Find the maximum price for each product offered in Madison
WITH MEMBER [Measures].[Max Value] AS MAX([Measures].[Price])
SELECT NON EMPTY {
[Measures].[Max Value]} ON 0,
NON EMPTY {
([Tb Product].[Name].[Name] ) } ON ROWS
FROM [DS715]
WHERE ([Tb Supplier].[City].&[Madison])
EDIT:
WITH MEMBER [Measures].[Max Price RANK] AS
RANK( ([Tb Product].[Name].currentmember),
ORDER( ([Tb Product].[Name].currentmember), [Measures].[Price - Tb Transactions], BDESC) )
SELECT
NON EMPTY {
[Measures].[Price - Tb Transactions] } ON COLUMNS,
NON EMPTY {
filter([Tb Product].[Name].[Name], [Measures].[Max Price RANK] <2 )} ON ROWS
FROM [DS715]
WHERE ( [Tb Supplier].[City].&[Madison] )
Now only one row for each, but with very large numbers
RANK function is what you need to use. In the example below I am listing all the Product categories with their subcategories and their internat sales
Query 1
select
{
[Measures].[Internet Sales Amount]
}
on columns,
non empty
([Product].[Category].[Category],[Product].[Subcategory].[Subcategory])
on rows
from
[Adventure Works]
Result
Now Lets modify the query to restrict to the member with max Internet Sale
WITH
MEMBER [Measures].[Internet Sales Amount Rank] AS
RANK( ([Product].[Category].currentmember,[Product].[Subcategory].CurrentMember),
ORDER( ([Product].[Category].currentmember,[Product].[Subcategory].[Subcategory].Members) , [Measures].[Internet Sales Amount], BDESC)
)
select
non empty
[Measures].[Internet Sales Amount]
on columns,
non empty
([Product].[Category].[Category],filter([Product].[Subcategory].[Subcategory],[Measures].[Internet Sales Amount Rank]<2))
on rows
from [Adventure Works]
Result
Edit
You left the city out that is why rank is not working. make the following changes
WITH MEMBER [Measures].[Max Price RANK] AS
RANK( ([Tb Product].[Name].currentmember,[Tb Supplier].[City].currentmember),
ORDER( ([Tb Product].[Name].currentmember,[Tb Supplier].[City].[City].members), [Measures].[Price - Tb Transactions], BDESC)
)
SELECT
NON EMPTY {
[Measures].[Price - Tb Transactions] } ON COLUMNS,
NON EMPTY {
([Tb Product].[Name].[Name],filter([Tb Supplier].[City].[City], [Measures].[Max Price RANK] <2 )}
ON ROWS
FROM [DS715]
I have a measure, Sales Amount. I want to rank customers within a divison by year for that measure. I need to also display that rank as a measure. The rank needs to start over every year. I am able to do customers by year and customers by division, but I can't seem to figure out how to combine them both so it iterates over both dimensions properly. Below is what I have for the customers by year. I have tried adding another Division set, creating another named set that I GENERATE with the YearsWithCustomers set, and RANK using that new named set. I seem to be super close to figuring this out but I think I am putting something in the wrong place. I got the idea to iterate over a set from one of Chris Webb's blogs, located here.
WITH
SET Years AS
TopPercent
(
[Sales and Forecast Date].[Calendar Year].[Year Number].MEMBERS
,100
,[Measures].[Sales Amount]
)
SET Customers AS
Filter
(
[Customer].[Customer Number].[Customer Number].MEMBERS
,
[Measures].[Sales Amount] > 0
)
SET YearsWithCustomers AS
Generate
(
Years
,Union
(
{[Sales and Forecast Date].[Calendar Year].CurrentMember}
,StrToSet
("
Intersect({},
{order(Customers,([Sales Amount],[Sales and Forecast Date].[Calendar Year].CurrentMember),desc)
as CustomerSet"
+
Cstr(Years.CurrentOrdinal)
+ "})"
)
)
,ALL
)
MEMBER [Measures].[Customer Rank] AS
Rank
(
[Customer].[Customer Number].CurrentMember
,StrToSet
("CustomerSet"
+
Cstr
(
Rank
(
[Sales and Forecast Date].[Calendar Year].CurrentMember
,Years
)
)
)
)
SELECT
{
[Customer Rank]
,[Measures].[Sales Amount]
} ON 0
,Order
(
Filter
(
(
YearsWithCustomers
,Customers
)
,
[Sales Amount] > 0
)
,[Sales Amount]
,desc
) ON 1
FROM [OrdersAndBudgets];
Here is what I currently have. I would expect to see 1, 2, 3, etc for the Rank measure. It should reset for each division for every year.
I like this sort of pattern:
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries] AS a
,{
(
a.CurrentMember
,[Product].[Product].[All]
)
+
//The top x prods
a.CurrentMember
*
TopCount
(
[AllProds]
,5
,[Measures].[Internet Sales Amount]
)
}
)
MEMBER [Product].[Product].[All].[Other Products] AS
Aggregate
(
[Country].CurrentMember * [Product].[Product].[Product].MEMBERS
-
[Top5Prods]
)
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,Hierarchize(
{
[Top5Prods]
,[AllCountries] * [Product].[Product].[All].[Other Products]
}
) ON ROWS
FROM [Adventure Works];
It returns the following:
There is quite an extensive thread here: Top X of Top Y with RestOf member where X and Y are hierarchies from different dimensions
I am trying to implement something as follows:
WITH MEMBER Measures.Test2 AS
Sum
(
{
[Date].[Calendar].[Calendar Year].&[2006]
,[Date].[Calendar].[Calendar Year].&[2007]
}
,[Measures].[Internet Sales Amount]
)
SELECT Measures.Test2 ON COLUMNS
FROM [Adventure Works];
But i want the new measure Test2 to be sliceable according to the Calendar Year dimension. So i want something like
SELECT {Measures.Test2} ON 0,
{[Date].[Calendar].[Calendar Year].[Calendar Year].MEMBERS} ON 1
FROM [Adventure Works];
This is giving the same value for both the years 2006 and 2007.
In essence i want to create a member by taking a subset of an existing measure and then using it for further calculations
This script is not valid mdx:
SELECT (Measures.Test2,[Date].[Calendar].[Calendar Year].[Calendar Year] ON COLUMNS
FROM [Adventure Works];
You have a single ( before Measures.
Also you look like you're about to add a tuple ON COLUMNS which is not allowed. Only sets are allowed on rows and columns:
SELECT
{Measures.Test2} ON 0,
{[Date].[Calendar].[Calendar Year].[Calendar Year].MEMBERS} ON 1
FROM [Adventure Works];
Try the following:
WITH
MEMBER Measures.Test2 AS
Sum
(
Intersect
(
{[Date].[Calendar].CurrentMember}
,{
[Date].[Calendar].[Calendar Year].&[2006]
,[Date].[Calendar].[Calendar Year].&[2007]
}
)
,[Measures].[Internet Sales Amount]
)
SELECT
[Measures].test2 ON COLUMNS
,{[Date].[Calendar].[Calendar Year].MEMBERS} ON ROWS
FROM [Adventure Works];
The above returns this:
Or maybe all you want is a subselect:
SELECT
[Measures].[Internet Sales Amount] ON COLUMNS
,{[Date].[Calendar].[Calendar Year].MEMBERS} ON ROWS
FROM
(
SELECT
{
[Date].[Calendar].[Calendar Year].&[2006]
,[Date].[Calendar].[Calendar Year].&[2007]
} ON 0
FROM [Adventure Works]
);
I am trying to work out how I can get a total for a level in a user defined hierarchy. For example if I do (using Adventure works here):
SELECT [Measures].[Internet Sales Amount] ON 0,
([Date].[Calendar Year].ALLMEMBERS * [Date].[Month of Year].ALLMEMBERS) ON 1
FROM [Adventure Works]
I get totals for each pair of year/month values.
How can I rewrite this query using the Calendar user hierarchy in the Date dimensions? Eg something like:
SELECT [Measures].[Internet Sales Amount] ON 0,
([Date].[Calendar].[Year] * [Date].[Calendar].[Month]) ON 1
FROM [Adventure Works]
You can use
SELECT [Measures].[Internet Sales Amount] ON 0,
Hierarchize([Date].[Calendar].[Calendar Year] + [Date].[Calendar].[Month]) ON 1
FROM [Adventure Works]
This will show you each year containing its value (which is the sum of the months contained in it) before the months.
The + is the short form of Union in MDX, and Hierarchize sorts a set in hierarchical order, which means parents before children.
And if you want something similar to your first result, the closest thing I can imagine would be via calculated measures like this:
WITH Member Measures.Year AS
IIf([Date].[Calendar].CurrentMember.Level IS [Date].[Calendar].[Calendar Year],
[Date].[Calendar].CurrentMember.Name,
Ancestor([Date].[Calendar].CurrentMember, [Date].[Calendar].[Calendar Year]).Name
)
Member Measures.Month AS
IIf([Date].[Calendar].CurrentMember.Level IS [Date].[Calendar].[Month],
[Date].[Calendar].CurrentMember.Name,
'All Months'
)
SELECT {
Measures.Year,
Measures.Month,
[Measures].[Internet Sales Amount]
}
ON 0,
Hierarchize([Date].[Calendar].[Calendar Year] + [Date].[Calendar].[Month]) ON 1
FROM [Adventure Works]
Note that calculated members need not return numbers, they can as well return strings.
Using allmembers as you have it should return you the ALL line and then each year and each month. If you are interested in only the all line you can change you query to:
SELECT [Measures].[Internet Sales Amount] ON 0,
([Date].[Calendar Year] * [Date].[Month of Year]) ON 1
FROM [Adventure Works]
Notice how it is specifying only the Dimension and the hierarchy.
If you wanted to get the data without the all line use the following:
SELECT [Measures].[Internet Sales Amount] ON 0,
([Date].[Calendar Year].children * [Date].[Month of Year].children) ON 1
FROM [Adventure Works]
SELECT
[Measures].[Internet Sales Amount] ON COLUMNS
,Tail
(
[Date].[Calendar Year].[Calendar Year].MEMBERS
,2
) ON ROWS
FROM [Adventure Works];
Above MDX query gives me output as :
Year Internet Sales Amount
CY 2003 $9,791,060.30
CY 2004 $9,770,899.74
I understood how this query worked but I want to create Calculated measure in a cube which will always give me sum of bottom 2 years. How to do this? I am a newbie to SSAS. I am good at designing simple measures and dimensions but when it comes to using MDX, I am mostly stuck.
PS: I tried using TopCount, BottomCount etc but here I want to order by "Year", which is a dimension.
Any help would be appreciated.
Thanks,
Parry
The following query calculates a measure for sum the the last 2 years of the Date dimension:
WITH
MEMBER [Measures].[Sales from the last 2 Years]
AS Aggregate( Tail( [Date].[Calendar Year].[Calendar Year].Members, 2)
, [Measures].[Internet Sales Amount]
)
SELECT { [Measures].[Sales from the last 2 Years]
} ON COLUMNS
, { Tail( [Date].[Calendar Year].[Calendar Year].Members, 2)
} ON ROWS
FROM [Adventure Works]
Other interesting query, would be calculating a measure for the sum of each year and its previous:
WITH
MEMBER [Measures].[Sales from 2 years]
AS Aggregate( { [Date].[Calendar Year].CurrentMember.PrevMember
: [Date].[Calendar Year].CurrentMember }
, [Measures].[Internet Sales Amount]
)
SELECT { [Measures].[Internet Sales Amount]
, [Measures].[Sales from 2 years]
} ON COLUMNS
, NON EMPTY
{ [Date].[Calendar Year].[Calendar Year]
} ON ROWS
FROM [Adventure Works]
It does a sum, because the aggregation type of the measure [Measures].[Internet Sales Amount] is Sum, and the Aggregate function aggregates according to the measure's aggregation type.
Key Concepts in MDX
Aggregate function reference
MDX is a hard topic to grasp; if you're starting out, I recommend you read the book MDX Solutions, 2nd edition.