How can i use a subquery or (WITH)statment in MDX Query? - sql

I have a CustomerToFactor as a Measure and Customer as a Dimension. Now I want to create a MDX code like this SQL code but I can't. because (WITH) statements has another meaning in MDX.
with Total_Customer(
select cus_id
,sum(ctf_price) cus_total_price
from dbo.Customer
join dbo.CustomertoFactor on cus_id = ctf_cus_id
group by cus_id
)
select cus_id
,cus_name
,ctf_date
,ctf_price
,(cus_total_price / 100 * ctf_price) as Price_pro_customer
from dbo.Customer
join dbo.CustomertoFactor on cus_id = ctf_cus_id
join Total_Customer on Total_customer.cus_id = dbo.Customer.cus_id
SELECT NON EMPTY { [Measures].[ctf_date]
,[Measures].[ctf_price]
, (?) Price_pro_customer
} ON COLUMNS
,NON EMPTY {[Customer].[Customer - cus_name].[Customer - cus_name].ALLMEMBERS}
FROM [CustomerToFactor]
Thanks for your Answers. but it doesn't work. Actually I want it to be grouped for every name you name. for Example: for the name Alex only the sum would have to be calculated for Alex(100+300 = 400) as well as Group by.

I do not really understand the point of the calculation :)
But anyway, in MDX you can have your own measures calculated like this:
WITH MEMBER [Measures].[Price_pro_customer] AS
(SUM([Measures].[ctf_price]) / 100 * [Measures].[ctf_price])
SELECT NON EMPTY { [Measures].[ctf_date]
,[Measures].[ctf_price]
,[Measures].[Price_pro_customer]
} ON COLUMNS
,NON EMPTY {[Customer].[Customer - cus_name].[Customer - cus_name].ALLMEMBERS}
FROM [CustomerToFactor]
I am not sure you'll get the same result as the SQL query though, since you have [Customer].[Customer - cus_name].[Customer - cus_name].ALLMEMBERS on the rows which basically does a GROUP BY on the customer name.
So if in the table you had several rows for the same customer the output of MDX query should be 1 row for each customer. The SUM([Measures].[ctf_price]) is also different since it sums over all customers

I think you should create a date dimension reference to ctf_date.
Then your mdx should be as below:
WITH MEMBER [Measures].[Price_pro_customer] AS
SUM([DimDate].[ctf_date].[All], [Measures].[ctf_price]) / 100 * [Measures].[ctf_price]
SELECT NON EMPTY {
[Measures].[ctf_price] ,
[Measures].[Price_pro_customer]
} ON COLUMNS ,
NON EMPTY {[Customer].[Customer - cus_name].[Customer - cus_name].ALLMEMBERS *
[DimDate].[ctf_date].[ctf_date].ALLMEMBERS} ON ROWS
FROM [CustomerToFactor]

Related

How to use SUM in this situation?

I have the following tables below and their schema:
INV
id, product code, name, ucost, tcost, desc, type, qoh
1,123,CPASS 700,1.00,5.00,CPASS 700 Lorem, COM,5
2,456,Shelf 5,2.00,6.00,Shelf 5 KJ, BR,3
GRP
id,type,desc
1,COM,COMPASS
2,BR,SHELF
Currently I have a query like this:
SELECT INV.*,GRP.DESCR AS CATEGORY
FROM INV LEFT JOIN GRP ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0
There is no problems with that query.
Right now,I want to know the SUM of the TCOST of every INV record where their QOH is 0.
In this situation, does that I mean all I have to do is to write a separate query like the one below:
SELECT SUM(TCOST)
FROM INV
WHERE QOH = 0
Does it make any sense for me to try and combine those two queries as one ?
First understand that SUM is the aggregate function hence either you can run the Query like
(SELECT SUM(TCOST) FROM INV WHERE QOH=0) as total
This will return Sum of TCOST in INV Table for mentioned condition.
Another approach is finding the Sum based on the some column (e.g. Type)
you could write query like
SELECT Type , SUM(TCOST) FROM INV WHERE QOH=0 GROUP BY type ;
Its not clear on what criteria you want to sum . But I think above two approaches would provide you fare idea .
Mmm, you could maybe use a correlated query, though i'm not sure it's the best approach since I'm not sure I understand what your attempting to do:
SELECT INV.*,
GRP.DESCR AS CATEGORY ,
(SELECT SUM(TCOST) FROM INV WHERE QOH=0) as your_sum
FROM INV LEFT JOIN GRP ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0
If you want only one value for the sum(), then your query is fine. If you want a new column with the sum, then use window functions:
SELECT INV.*, GRP.DESCR AS CATEGORY,
SUM(INV.TCOST) OVER () as sum_at_zero
FROM INV LEFT JOIN
GRP
ON INV.TYPE = GRP.TYPE
WHERE INV.QOH = 0;
It does not make sense to combine the queries by adding a row to the first one, because the columns are very different. A SQL result set requires that all rows have the same columns.

How to find sum of each group in Hierarchy in MDX

In the example below I want to find sum of each group. Can someone correct my MDX query to get the desired result for GroupCount Column.
with member [GroupCount] as
aggregate([Department].[Department ID].currentmember.parent,
[Measures].[Pay Frequency])
select {[Department].[Group Name].[all].children*
[Department].[Department ID].[all].children
} on rows,
{[Measures].[Pay Frequency],[GroupCount]} on columns
from test
The result I am getting from the above query is:
However I need the output as :
Is it like this?
with member [GroupCount] as
(
[Department].[Group Name].CURRENTMEMBER,
[Department].[Department ID].[All],
[Measures].[Pay Frequency]
)
select {[Department].[Group Name].[all].children*
[Department].[Department ID].[all].children
} on rows,
{[Measures].[Pay Frequency],[GroupCount]} on columns
from test;

MDX - group dimension by name

I have a dimension (page_type) where the names are not unique (so two keys can have the same name). Now I would like to see the clicks by page_type-name.
The following query unfortunately show the dimension names, but one line per key.
SELECT
{[Measures].[count_clicks]} ON COLUMNS,
[page_type].[page_type].members ON ROWS
FROM
[customer_journey]
The result:
category 150.000
product 100.000
category 80.000
...
How can I change this query, to get only one line per page_type?
category 230.000
product 100.000
...
This is slow but does this work:
with set SetOfPagesWithSameName as
filter
(
[page_type].[page_type].members as p,
p.current.name = [page_type].[page_type].currentmember.name
)
member Measures.TotalCountOFClicks as
sum(
existing SetOfPagesWithSameName,
[Measures].[count_clicks]
)
member Measures.CountSimilarPagesGrt1 as
IIF(SetOfPagesWithSameName.count > 0 , 1, null)
select
NonEmpty([page_type].[page_type].members, Measures.CountSimilarPagesGrt1) on 1,
Measures.TotalCountOFClicks on 0
from [customer_journey]

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 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)