SQL subselect, group by, sum equivalent in MDX(SSAS) - ssas

I have a problem with creation of calculated member in SSAS.
Fact table:
Date Store Product Sales_in_USD
--------------------------------------------------
2016-07-01 Store1 Product1 50
2016-07-01 Store1 Product2 100
2016-07-01 Store2 Product3 70
2016-07-01 Store2 Product2 85
Dimensions:
Dates,Stores,Products
I want to get something like that:
If I filter by some product I want to get all sales by this store and date that include sales by filtered product+another products, for example I want filter by Product1:
SQL code:
select sum(Sales_in_USD)
from [Fact table]
where Store in (select Store from [Fact table] where Product="Product1")
Executing this sql code I get all Sales by Store1.
How I can create it with MDX when I want create a calculated member?
Output of calculated member must be the next:
Product Total_Sales_By_Store
------------------------------
Product1 50+100=150
Product2 50+100+70+85=305
Product3 70+85=155

1 - Determine the valid stores for the selected product.
NonEmpty(
[Store].[Store Name].MEMBERS,
([Product].[Product].Currentmember,[Measures].[Sales_in_USD])
)
2 - Once you have the stores for the current product, you want to calculate the sum of values for the possible tuples(cross join).
with member Measures.[Total Sum of Stores] as
sum(
[Product].[Product].Currentmember *
NonEmpty
(
[Store].[Store Name].MEMBERS,
([Product].[Product].Currentmember,[Measures].[Sales_in_USD])
)
,
[Measures].[Sales_in_USD]
)
select Measures.[Total Sum of Stores] on 0
from [YourCube]
where [Product].[Product].[Product1]

SELECT
[Measures].[Sales_in_USD] ON 0,
{[Store].[Store Name].MEMBERS,
[Product].[Product].MEMBERS} ON 1
FROM [Cube Name];
For your requirement, you really don't need a calculated member, since the measures will do the job for you
For Particular Product Name Product1, then
SELECT
[Measures].[Sales_in_USD] ON 0,
{[Product].[Product].&[Product1],
[Store].[Store Name].MEMBERS
} ON 1
FROM [Cube Name];

I think Sourav has pretty much nailed it but it could be more general?
WITH
MEMBER [Measures].[Total Sum of Stores] AS
SUM(
NONEMPTY(
[Store].[Store Name].MEMBERS,
(
[Product].[Product].Currentmember
,[Measures].[Sales_in_USD]
)
)
,[Measures].[Sales_in_USD]
)
SELECT
[Measures].[Total Sum of Stores] on 0,
[Product].[Product].[Product].MEMBERS ON 1
FROM [YourCube];

Related

How to implement "greater than" based on dimension value in MDX

I would like to query the total sales of each country with the GDP growth rate of more than 3. So far, I can display the sales information of each country like such:
SELECT
{[Measures].[Sales]} ON 0,
{[Dim Company Info].[LOC].ALLMEMBERS} ON 1
FROM [Database]
But then I am still blank on how to query all GDP growth rate of more than 3. I have searched SO and found filter to be the answer, however, I do not know where to include it in my code above. How do I go about this?
Edit: I have tried the followings, but I do not think that is what I am supposed to do:
WHERE ([Dim Company Info].[Gdp Growth].&[3] : [Dim Company Info].[Gdp Growth].&[3].LastChild)
and
SELECT
{[Measures].[SALES]} ON 0,
{FILTER([Dim Company Info].[LOC].MEMBERS, [Dim Company Info].[Gdp Growth] > 3)} ON 1
FROM [766 Database]
and
SELECT
{[Measures].[SALES]} ON COLUMNS,
{[Dim Company Info].[LOC].MEMBERS} ON ROWS
FROM [766 Database]
WHERE FILTER([Dim Company Info].[Gdp Growth], [Dim Company Info].[Gdp Growth] > 2)
You can use your below expression when the dimension members are numericly arranged
WHERE ([Dim Company Info].[Gdp Growth].&3 : [Dim Company Info].[Gdp
Growth].&3.LastChild)
with a slight correction
WHERE ([Dim Company Info].[Gdp Growth].&[3] : [Dim Company Info].[Gdp Growth].[Gdp Growth].LastChild)
However if that is not the case, then you need to follow the below method.
I am reporting the product with the max quantity.
select {[Measures].[Internet Sales Amount]} on 0,
non empty
([Product].[Product].[Product],[Promotion].[Max Quantity].[Max Quantity]) on 1
from [Adventure Works]
Now lets manipulate the max quantity to make it behave like a measure.
with
member measures.test
as
case when [Measures].[Internet Sales Amount]>0 then
(nonempty(([Product].[Product].currentmember,[Promotion].[Max Quantity].[Max Quantity]),[Measures].[Internet Sales Amount])).item(0).item(1).name
else
null end
select
{[Measures].[Internet Sales Amount],measures.test}
on 0,
non empty ([Product].[Product].[Product] )
on 1
from [Adventure Works]
Now you can use the filter, but we need to cast(note the use of CInt) the data too
with
member measures.test
as
case when [Measures].[Internet Sales Amount]>0 then
Cint((nonempty(([Product].[Product].currentmember,[Promotion].[Max Quantity].[Max Quantity]),[Measures].[Internet Sales Amount])).item(0).item(1).name)
else
null end
select
{[Measures].[Internet Sales Amount],measures.test}
on 0,
non empty (
filter(
[Product].[Product].[Product]
,measures.test>0)
)
on 1
from [Adventure Works]

In MDX, the price rank of a given number is 0

I have an OLAP cube containing the type price sum for each of number.
Using MDX, how can I output the rank of a given number?
Result should be as follows:
Heare is the MDX query, but all rank values are 0. What is wrong in query?
WITH MEMBER [Measures].[Rank Sum of price] AS
RANK([NUM_1].[All Numbers].CURRENTMEMBER
,[NUM_1].[All Numbers]
,[Measures].[Sum of price])
SELECT
{
[Measures].[Sum of price]
, [Measures].[Rank Sum of price]
}
ON COLUMNS,
[NUM_1].[All Numbers]
ON ROWS
FROM schema1
Maybe do your ordering in a custom set before hitting the rank function:
WITH
SET OrderedNums AS
Order
(
[NUM_1].[All Numbers].[All Numbers].MEMBERS
,[Measures].[Sum of price]
,BDESC
)
MEMBER [Measures].[Rank Sum of price] AS
Rank
(
[NUM_1].[All Numbers].CurrentMember
,OrderedNums
)
SELECT
{
[Measures].[Sum of price]
,[Measures].[Rank Sum of price]
} ON 0
,[NUM_1].[All Numbers].[All Numbers].MEMBERS ON 1
FROM schema1;

MDX Running total on every date member

I use the following MDX calculation to get the stock value per day:
SUM({NULL:[Date].[Calendar Hierarchy].CURRENTMEMBER} * [Measures].[Qty])
However this is giving me the following result
Date QtyOnHand
1/1/2015 10
4/1/2015 15
5/1/2015 16
Mark that the dates 2/1/2015 and 3/1/2015 are not shown, because there are no transactions on them.
I would like to get these shown to get the following result:
Date QtyOnHand
1/1/2015 10
2/1/2015 10
3/1/2015 10
4/1/2015 15
5/1/2015 16
How can I adjust my MDX statement to this?
Does IsEmpty help?
SUM(
{NULL:[Date].[Calendar Hierarchy].CURRENTMEMBER}
* IIF(
IsEmpty([Measures].[Qty])
,0
,[Measures].[Qty]
)
)
If it helps then it won't help performance.
I've tested the above and unsure why you do the cross-join inside the Sum - more standard is just to use the second argument.
This AdvWrks script is an example of your scenario i.e. there are gaps in the data:
SELECT
{[Measures].[Internet Sales Amount]} ON 0
,{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20051201]
} ON 1
FROM [Adventure Works];
Here is the query using IsEmpty (with IIF):
WITH
MEMBER [Measures].[roll] AS
Sum
(
{[Date].[Calendar].[Date].&[20050801] : [Date].[Calendar].CurrentMember}
,IIF
(
IsEmpty([Measures].[Internet Sales Amount])
,0
,[Measures].[Internet Sales Amount]
)
)
SELECT
{[Measures].[Internet Sales Amount],[Measures].[roll]} ON 0
,{
[Date].[Calendar].[Date].&[20050801]
:
[Date].[Calendar].[Date].&[20051201]
} ON 1
FROM [Adventure Works];
Some of the results are the following:
So in your scenario I think this is very similar:
SUM(
{NULL:[Date].[Calendar Hierarchy].CURRENTMEMBER}
, IIF(
IsEmpty([Measures].[Qty])
,0
,[Measures].[Qty]
)
)

MDX, first SUM then AVERAGE

I have a fact model that contains the following data:
WorkOrderNumber | WorkOrderLineNumber | Cost
So I have a dimension WorkOrder:
[WorkOrder].[WorkOrderNumber]
[WorkOrder].[WorkOrderLineNumber]
And a Measure group with the following Measure:
[Measures].[Cost]
I am trying to create a calculate measure:
[Measures].[Average WorkOrder Cost]
This must be calculated by Summing up the values per Work Order and afterwards taking an average of all these sums per workorders.
However I can not seem to get it working.
CASE WHEN [WorkOrder].[WorkOrder].CurrentMember = [WorkOrder].[WorkOrder].[All]
THEN
/* the work order is not selected -> AVG*/
DIVIDE(SUM(),[Measures].[Cost]), Count()) ))
ELSE
/* the Work Order is selected -> SUM*/
SUM([Measures].[Cost])
END
Here is an example of taking an average per sales order using the Adventure Works cube. You could replace with your [Cost] and [WorkOrderNumber]...
with member [CalculatedAvg] as
AVG([Internet Sales Order Details].[Sales Order Number].[Sales Order Number], [Measures].[Internet Sales Amount])
, FORMAT_STRING = "$#,##0.00"
select
{
[Measures].[Internet Sales Amount],
[Measures].[Internet Order Count],
[Measures].[Internet Average Sales Amount],
[CalculatedAvg]
} on 0,
[Date].[Calendar].[Calendar Year].members on 1
from
[Direct Sales]
for example...
AVG([WorkOrder].[WorkOrderNumber].[WorkOrderNumber], [Measures].[Cost])

MDX Count over time (years - not within a year)

I'd like to be able to rollup the count of commitments to a product over years -
The data for new commitments in each year looks like this:
Year | Count of new commitments | (What I'd like - count of new commitments to date)
1986 4 4
1987 22 26
1988 14 40
1989 1 41
I know that within a year you can do year to date, month to date etc, but I need to do it over multiple years.
the mdx that gives me the first 2 columns is (really simple - but I don't know where to go from here):
select [Measures].[Commitment Count] on 0
, [Date Dim].[CY Hierarchy].[Calendar Year] on 1
from [Cube]
Any help would be great
In MDX something along the line:
with member [x] as sum(
[Date Dim].[CY Hierarchy].[Calendar Year].members(0) : [Date Dim].[CY Hierarchy].currentMember,
[Measures].[Commitment Count]
)
select [x] on 0, [Date Dim].[CY Hierarchy].[Calendar Year] on 1 from [Cube]
Use a common table expression:
with sums (year,sumThisYear,cumulativeSum)
as (
select year
, sum(commitments) as sumThisYear
, sum(commitments) as cumulativeSum
from theTable
where year = (select min(year) from theTable)
group by year
union all
select child.year
, sum(child.commitments) as sumThisYear
, sum(child.commitments) + parent.cumulativeSum as cumulativeSum
from sums par
JOIN thetable Child on par.year = child.year - 1
group by child.year,parent.cumulativeSum
)
select * from sums
There's a bit of a "trick" in there grouping on parent.cumulativeSum. We know that this will be the same value for all rows, and we need to add it to sum(child.commitments), so we group on it so SQL Server will let us refer to it. That can probably be cleaned up to remove what might be called a "smell", but it will work.
Warning: 11:15pm where I am, written off the top of my head, may need a tweak or two.
EDIT: forgot the group by in the anchor clause, added that in