I am new in MDX and currently struggling in this. I badly need help on how to get the total count of customers based on the WHERE clause. Please see my query below. I am trying to implement pagination so I need the total count to get the number of pages to be displayed. Is that possible?
WITH
MEMBER [Measures].[DS_TY] AS
'([Transaction Type].[All Transaction Type].[Daily Sales], [Measures].[TY])'
MEMBER [Measures].[ST_TY] AS
'([Transaction Type].[All Transaction Type].[Stock Transfer], [Measures].[TY])'
MEMBER [Measures].[IS_TY] AS
'([Transaction Type].[All Transaction Type].[IServ], [Measures].[TY])'
MEMBER [Measures].[TOT_TY] AS
'([Transaction Type].[All Transaction Type], [Measures].[TY])'
MEMBER [Measures].[DS_LY] AS
'([Transaction Type].[All Transaction Type].[Daily Sales], [Measures].[LY])'
MEMBER [Measures].[ST_LY] AS
'([Transaction Type].[All Transaction Type].[Stock Transfer], [Measures].[LY])'
MEMBER [Measures].[IS_LY] AS
'([Transaction Type].[All Transaction Type].[IServ], [Measures].[LY])'
MEMBER [Measures].[TOT_LY] AS
'([Transaction Type].[All Transaction Type], [Measures].[LY])'
MEMBER [Measures].[2] AS
'iif([LY]=0 Or [LY]=Null, Null, ([TY] - [LY])/[LY])'
MEMBER [Measures].[4] AS
'[1] - [TY]'
MEMBER [Measures].[6] AS
'[5] - [TY]'
SET smeasures AS
'{[DS_TY],[ST_TY],[IS_TY],[TOT_TY],[DS_LY],[ST_LY],[IS_LY],[TOT_LY],[1],[2],[3],[4],[5],[6]}'
MEMBER [Measures].[TY] AS
'[Measures].[Gross Up Sales YTDTY Amt (Allocation)]'
MEMBER [Measures].[LY] AS
'[Measures].[Gross Up Sales YTDLY Amt (Allocation)]'
MEMBER [Measures].[1] AS
'[Measures].[Quota Amt YTDTY (Allocation)]'
MEMBER [Measures].[3] AS
'[Measures].[%Perf YTDTY GrossUp (Allocation)]'
MEMBER [Measures].[5] AS
'[Measures].[Quota Annual Amt TY (Allocation)]'
SELECT smeasures ON COLUMNS,
NON EMPTY ORDER (
{
[Client Customer].[Client Customer].[Customer].members
},
[Client Customer].currentmember.name,
basc
) ON ROWS
FROM [CClient]
WHERE (
{
[Time].[Time].[Year].[2020].[November]
},
[Transaction Type].[All Transaction Type],
{[Client Org].[Level 02]}-
DESCENDANTS({[Client Org].&[D2_BTR2099_01], [Client Org].&[D2_DTR2099_99], [Client Org].&[D2_GTR2099_02]})
)
Thank you in advance!
You need to use Subset for paging. Let me walk you through an example. Its based on Microsoft AdventureWorks
So I want to see the INTERNET SALES AMOUNT of all PRODUCTS in FRANCE for 2012.
select {[Measures].[Internet Sales Amount]}on 0,
order (
filter({[Product].[Product].[Product]},[Measures].[Internet Sales Amount]>0)
,[Measures].[Internet Sales Amount],desc)
on 1
from
[Adventure Works]
where
([Date].[Calendar Year].&[2012],[Geography].[Country].&[France])
This result is
These are 94 rows, since the header is also counted so SSMS shows 95
Now lets change the query just to return the number of rows without returning actual rows. For this we use a calculated measure, which will have the entire set expresion of your rows axis. We then apply count function on this
---total Row Count
with member
Measures.ResultSetCount
as
(filter({[Product].[Product].[Product]},[Measures].[Internet Sales Amount]>0)).count
select Measures.ResultSetCount on 0
from [Adventure Works]
where
([Date].[Calendar Year].&[2012],[Geography].[Country].&[France])
We now know we have 94 rows. Now Lets returns them in pages of 10.
------Paging
select {[Measures].[Internet Sales Amount]}on 0,
subset(
order (
filter({[Product].[Product].[Product]},[Measures].[Internet Sales Amount]>0)
,[Measures].[Internet Sales Amount],desc)
,0,10)
on 1
from
[Adventure Works]
where
([Date].[Calendar Year].&[2012],[Geography].[Country].&[France])
The result is for page 1, replace the "0" with 1, before 10 in ",0,10)" you will have page 2 and so on.
Related
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];
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]
I want to calculate percentage of individual Categories, Here is my mdx code.
WITH
MEMBER [Measures].[Individual_Total] AS ([DIM RATING STRINGS].[LABEL]*[Measures].AGG_RATING Count])
SELECT
NONEMPTY {
[Measures].[AGG_RATING Count],[Measures].[Individual_Total]
} ONColumns,
([DIM STRUCTURE].[PARENT CODE].&[M01]&[M]:[DIM STRUCTURE].[PARENT CODE].&[M11]&[M],
[DIM TAILORING].[TAILORING_LABEL].[TAILORING_LABEL],
{[DIM RATING STRINGS].[LABEL].[LABEL],[DIM RATING STRINGS].[LABEL]}
) onrows
FROM [Cube]
Here is the output
In this output we have 4 categories like ""External Drivers ,stretegy,Business operation and governance.
I need to calculate percentage of different color with in the same category.
For example if we take "External Drivers" then Calculation should be like
amber = 15/28 * 100, green = 5/28/*100 etc because 28 is the sum of external drivers.
Please tell me how to do this thing in mdx.
thanks
Here you can compare with my solution, it will give you the percent of the parent.
with
member [Measures].[Percent of parent] as
([Measures].[Order Quantity]) /
([Product].[Product Categories].currentmember.parent,
[Measures].[Order Quantity])
,format_string = "percent"
SELECT
{([Measures].[Order Quantity]),
([Measures].[Percent of parent])} ON COLUMNS,
{[Product].[Product Categories].[Category].&[3]} *
{[Product].[Subcategory].[Subcategory].Members} *
{[Product].[Style].[Style].Members} *
{[Product].[Product].members}
ON ROWS
FROM [Cube]
I donĀ“t know if i read your dimensions correctly but maybe your member should look something like:
with member [Measures].[Percent] as
[Measures].[AGG_RATING Count] /
([DIM RATING STRINGS].[LABEL].CURRENTMEMBER.PARENT,
[Measures].[AGG_RATING Count])
, format_string = "percent"
Using the illustrated mockup
(Note not all DimB members show so the total for DimA is larger than the sum of the displayed DimB, ignore this):
Query is showing (months,revenue) on 0, (dima,dimb) on 1 from cube
I would like some assistance in creating the calculated member that would calculate the running total across "Months" here (not a real time dimension).
Earlier i was using this one, but it was wrong on so many levels:
[Measures].[Accumulated Revenue] =
IIF(
([DimMonths].[Months].CurrentMember,[Measures].[Revenue]) = 0
AND ([DimMonths].[Months].CurrentMember.NextMember,[Measures].[Revenue]) = 0
,
IIF(
AGGREGATE({
[DimMonths].[Months].CurrentMember :
[DimMonths].[Months].Parent.LastChild
},[Measures].[Revenue]) = 0
,
NULL
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember.PrevMember
}
,[Measures].[Revenue])
)
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember
}
,[Measures].[Revenue])
)
Sounds like a job for a "scoped assignment". Basically, using a scoped assignment, you can overwrite the value of your calculated measure along the [Member_DimA_01] slice so that these values represent a running total instead of a sum of children.
Here's a good tutorial from Chris Webb on scoped assignments to help get you started...
Edit: here's a template for the running total calculation...
WITH
SET [Months] AS
{
[Date].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Month].&[2011 - Dec]
}
MEMBER [Measures].[Running Total] AS
SUM(
{
[Date].[Calendar Hierarchy].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Hierarchy].CurrentMember
}
,[Measures].[Revenue]
)
SELECT
NON EMPTY{
[Months]
} ON 0,
NON EMPTY{
[DimA].[Member].Allmembers *
[DimB].[Member].Allmembers
} ON 1
FROM
[<<cube name>>]
WHERE
[Measures].[Revenue Running Total]
I have the following Problem:
Select
{
[Measures].[PerformanceTotalYtd]
} on columns,
Non Empty{
Except(([Desk].[DeskName].[Trade].Members,[Time].[Year-Month-Day].[Day].&[2012]&[1]&[10]),([Desk].[DeskName].[Trade].Members,[Time].[Year-Month-Day].[Day].&[2012]&[1]&[09]))
} on rows
from [Cube]
where ([Entity].[Entity].&[9], [Audience].[View].&[GOD])
It exists a Dimension with the Name Desk. This Dimension has a Hierarchy with the name DeskName. The lowest Level ist Trade.
Desk: -Total -Segment -BusinessArea -Department -4th Level Portfolio -Desk -Trade
With the Query showing below, i want to show all Trades, that have the Measure "PerformanceTotalYtd" != NULL on the Date of 2012/01/10 except the Trades with the Measure "PerformanceTotalYtd" != NULL on the Date of 2012/01/09 !
Example:
Trades with Measure PerformanceTotalYtd on the 2012/01/10:
ABC 12,99
DEF 3,22
GHI 55,60
Trades with Measure PerformanceTotalYtd on the 2012/01/09:
ABC 80,00
DEF 8,78
I want the following Result because the Trade "GHI" doesn't exists on the 2012/01/09 and is new:
GHI 55,60
My Query showing below have this result:
ABC 12,99
DEF 3,22
GHI 55,60
It doesn't delete the existing Trades from the 2012/01/09.
I have a Solution in SQL but want to make it in MDX:
SELECT DD.Code, Sum(PerformanceTotalYtd) as TOTAL
FROM [Reporting_DB].[Star].[Fact_PerformanceTotal] FIS
inner join Star.Dimension_Desk DD on FIS.DeskID = DD.DeskID
WHERE FIS.TimeID = 20120110 and FIS.EntityID = 9 AND DD.Code not in ( SELECT DD.Code
FROM [Reporting_DB_HRE].[Star].[Fact_PerformanceTotal] FIS inner join Star.Dimension_Desk DD on FIS.DeskID = DD.DeskID WHERE FIS.TimeID = 20120109 and FIS.EntityID = 9 group by DD.Code)group by DD.Code
Can anybody help me please? I can't find a solution.
Sorry for my bad english!
Alex
I have found a similar example in the Adventure Works cube:
The set {[Customer].[City].&[Bell Gardens]&[CA], [Customer].[City].&[Bellevue]&[WA], [Customer].[City].&[Bellflower]&[CA]} has 3 values for [Measures].[Internet Sales Amount] in [Date].[Calendar Year].&[2002], and only 2 values in [Date].[Calendar Year].&[2004]. So we need to show measure value for member in 2002 where measure value == null in 2004.
The next MDX query achieves the desired result:
with set S as '{[Customer].[City].&[Bell Gardens]&[CA], [Customer].[City].&[Bellevue]&[WA], [Customer].[City].&[Bellflower]&[CA]}'
select
[Measures].[Internet Sales Amount] on 0,
non empty { Filter(S, IsEmpty(([Date].[Calendar Year].&[2004], [Measures].[Internet Sales Amount]))) } on 1
from [Adventure Works]
where ([Date].[Calendar Year].&[2002])
I tried to modify your example accordingly, but can't test it. Here it is:
select
{ [Measures].[PerformanceTotalYtd] } on 0,
non empty { Filter([Desk].[DeskName].[Trade].Members, IsEmpty(([Time].[Year-Month-Day].[Day].&[2012]&[1]&[09], [Measures].[PerformanceTotalYtd]))) } on 1
from [Cube]
where ([Entity].[Entity].&[9], [Audience].[View].&[GOD], [Time].[Year-Month-Day].[Day].&[2012]&[1]&[10])
In short: use Filter instead of Except.
I have the Solution for my Problem. Following Query shows the same Result as the Query of Dmitry Polyanitsa! Have a nice Day guys!
with
set [Trades Today] as NonEmpty([Desk].[DeskName].[Trade].Members, ([Measures].[PerformanceTotalYtd], [Time].[Year-Month-Day].[Day].&[2012]&[1]&[10]))
set [Trades Yesterday] as NonEmpty([Desk].[DeskName].[Trade].Members, ([Measures].[PerformanceTotalYtd], [Time].[Year-Month-Day].[Day].&[2012]&[1]&[9]))
set [Trades Difference] as Except([Trades Today], [Trades Yesterday])
Select
{
[Measures].[PerformanceTotalYtd]
} on columns,
Non Empty{
[Trades Difference]
} on rows
from [Cube]
where ([Entity].[Entity].&[9], [Audience].[View].&[GOD])