MDX query - limiting the result through a range constraint - mdx

This is a MDX query generated through Saiku Analytics. I'd like to limit the list to have only those with [Is Applied] > 10. Please let me know how I can accomplish this.
WITH
SET [~ROWS] AS
{[Applicant Usage].[Geo].[Citizenship Country].Members}
SELECT
NON EMPTY {[Measures].[Is Applied]} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [Application Fact]

Filter is the usual way to accomplish this in mdx:
WITH
SET [~ROWS] AS
FILTER(
{[Applicant Usage].[Geo].[Citizenship Country].Members}
,[Measures].[Is Applied] > 10
)
SELECT
NON EMPTY {[Measures].[Is Applied]} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [Application Fact]
This is the documentation for the SSAS implementation of filter:
https://msdn.microsoft.com/en-us/library/ms146037.aspx

Related

MDX: Calculate percentage from a measure present in the same dimension

I am learning MDX and I have a question to create a percentage.
Basically, I extract data from Google Analytics API for multiple sets of pages.
For each set, I extract the number of UniquePageviews.
The SQL columns looks like that:
date
deviceCategory
medium
uniquePageviews
transactions
set_of_page (the rows contain the name of the set of pages. To simplify: 1. First, 2. Second, 3. Third )
Brand (Brand A, Brand B)
Market (Market X, Market Y)
Here is the current view I have:
http://i.stack.imgur.com/ZTC30.png
What I want to have is the percentage of UniquePageviews from the set of page 1 to 2 and from 2 to 3 So: UniquePageviews 2/Uniquepageviews 1 & UniquePageviews 3/Uniquepageviews 2.
http://i.stack.imgur.com/xf2gc.png
Do you know a simple way to do that in MDX?
Here is the code I have for now to display the pageviews:
WITH
SET [~COLUMNS_Brand_Brand] AS
SET [~COLUMNS_Market_Market] AS
{[Market].[Market].Members}
SET [~COLUMNS_set_of_page segment_set_of_page] AS
{[set_of_page].[set_of_page].Members}
SET [~ROWS] AS
{[Date].[Date].Members}
SELECT
NON EMPTY NonEmptyCrossJoin([~COLUMNS_Brand_Brand], NonEmptyCrossJoin([~COLUMNS_Market_Market], [~COLUMNS_set_of_page_set_of_page])) ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [MySQL_Cube]
Thanks a lot!
At the moment your mdx is picking up the measure implicitly? All mdx queries need something to measure so your current script must be picking up the default cube measure - I'll call this [Measures].[NumTransactions].
Also your first SET seems to be blank. Therefore lets assume the full, explicit script is:
WITH
SET [~COLUMNS_Brand_Brand] AS {[Brand].[Brand].[All]}
SET [~COLUMNS_Market_Market] AS
{[Market].[Market].Members}
SET [~COLUMNS_set_of_page segment_set_of_page] AS
{[set_of_page].[set_of_page].Members}
SET [~ROWS] AS
{[Date].[Date].Members}
SELECT
NON EMPTY NonEmptyCrossJoin([~COLUMNS_Brand_Brand], NonEmptyCrossJoin([~COLUMNS_Market_Market], [~COLUMNS_set_of_page_set_of_page])) ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [MySQL_Cube]
WHERE [Measures].[NumTransactions];
I use MS SSAS so a little unsure of nitation that works with you but just to help me I'll switch to the * operator for cross-joins:
WITH
SET [~COLUMNS_Brand_Brand] AS {[Brand].[Brand].[All]}
SET [~COLUMNS_Market_Market] AS
{[Market].[Market].Members}
SET [~COLUMNS_set_of_page segment_set_of_page] AS
{[set_of_page].[set_of_page].Members}
SET [~ROWS] AS
{[Date].[Date].Members}
SELECT
NON EMPTY
[~COLUMNS_Brand_Brand]
*[~COLUMNS_Market_Market]
*[~COLUMNS_set_of_page_set_of_page] ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [MySQL_Cube]
WHERE [Measures].[NumTransactions];
I'm hoping (as untested and I'm a little unsure all context will be retained) that we can just add a custom meassure that divides the current page by the previous one to get the percentage:
WITH
SET [~COLUMNS_Brand_Brand] AS {[Brand].[Brand].[All]}
SET [~COLUMNS_Market_Market] AS
{[Market].[Market].Members}
SET [~COLUMNS_set_of_page segment_set_of_page] AS
{[set_of_page].[set_of_page].Members}
SET [~ROWS] AS
{[Date].[Date].Members}
MEMBER [Measures].[NumTransactionsPercent] AS
[set_of_page].CURRENTMEMBER
/ [set_of_page].CURRENTMEMBER.LAG(1)
SELECT
NON EMPTY
[~COLUMNS_Brand_Brand]
*[~COLUMNS_Market_Market]
*[~COLUMNS_set_of_page_set_of_page] ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [MySQL_Cube]
WHERE [Measures].[NumTransactionsPercent]; //[Measures].[NumTransactions];

Slow MDX query when it contains 2 or more levels of the same dimension

I have a Dimension in Mondrian with the following levels:
-Dimension - Time by Minute
--Level - Hour
--Level - Minute
If I make a query using a single level, it takes a few seconds to process. However, if I add both levels to the query, the query will take half an hour.
What is more, if I duplicate the dimension into 2 so each of them has one of the levels, the Query will also take seconds.
Single level query:
WITH
SET [~COLUMNS] AS
{[Event].[Event].[Event Name].Members}
SET [~ROWS] AS
{[Time by Minute].[Time by Minute].[Minute].Members}
SELECT
NON EMPTY [~COLUMNS] ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [spdoc views]
Query with 2 levels:
WITH
SET [~COLUMNS] AS
{[Event].[Event].[Event Name].Members}
SET [~ROWS] AS
Hierarchize({{[Time by Minute].[Time by Minute].[Hour].Members}, {[Time by Minute].[Time by Minute].[Minute].Members}})
SELECT
NON EMPTY [~COLUMNS] ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [spdoc views]
Any ideas why this might happen?
So basically this happens because of Mondrian:
One of the key performance optimisations in Mondrian is to use native.crossjoin. However, since both levels belong to the same dimension it is not possible to perform it. Thus, a solution would be to separate the levels in several dimensions when they are going to be part of the same set.
"Why" I'm not sure.
There are various things you could try to speed the query up.
Try using a cross-join to take advantage of auto-exists behaviour & also move the Hierarchize inside the SELECT
WITH
SET [~COLUMNS] AS
{[Event].[Event].[Event Name].Members}
SET [~ROWS] AS
[Time by Minute].[Time by Minute].[Hour].Members
* [Time by Minute].[Time by Minute].[Minute].Members
SELECT
NON EMPTY [~COLUMNS] ON COLUMNS,
NON EMPTY Hierarchize([~ROWS]) ON ROWS
FROM [spdoc views];
Better still would be to apply NonEmpty to the set [~ROWS]. Do you have a measure you can use for this?:
WITH
SET [~COLUMNS] AS
{[Event].[Event].[Event Name].Members}
SET [~ROWS] AS
NonEmpty(
[Time by Minute].[Time by Minute].[Hour].Members
* [Time by Minute].[Time by Minute].[Minute].Members
, [Measures].[SomeMeasureInCube]
)
SELECT
NON EMPTY [~COLUMNS] ON COLUMNS,
NON EMPTY Hierarchize([~ROWS]) ON ROWS
FROM [spdoc views];

MDX filtering by multiple dimension members

Problem
I need to create a report which will list a number of accounts that match certain criteria - simulationDate, statisticPeriod, region.
Right now my query looks like this:
WITH MEMBER [Measures].[Count] as 1
SELECT [Measures].[Count] ON COLUMNS,
NON EMPTY
Crossjoin(
[Account].[Account Number].ALLMEMBERS,
{[simulationDate].[day].&[10010101]},
{[statisticPeriod].[period].&[201201]},
{[region].[code].&[SO]}
)
ON COLUMNS
FROM [myWH]
Is this cross-dimensional filtering okay?
This is slightly more modern using the * notation instead of the Crossjoin function:
WITH
MEMBER [Measures].[Count] AS 1
SELECT
[Measures].[Count] ON COLUMNS
,NON EMPTY
[Account].[Account Number].ALLMEMBERS*
{[simulationDate].[day].&[10010101]}*
{[statisticPeriod].[period].&[201201]}*
{[region].[code].&[SO]} ON COLUMNS
FROM [myWH];
I'm assuming that your custom measure [Measures].[Count] is just a place-holder?
This table will be very wide if you have that cross-join on COLUMNS but that might just be a typo:
WITH
MEMBER [Measures].[Count] AS 1
SELECT
[Measures].[Count] ON COLUMNS,
NON EMPTY
[Account].[Account Number].ALLMEMBERS*
{[simulationDate].[day].&[10010101]}*
{[statisticPeriod].[period].&[201201]}*
{[region].[code].&[SO]} ON ROWS
FROM [myWH];
You have added the keywords NON EMPTY in front of the rows cross-join. This is telling the processor to exclude any rows that are empty - empty for [Measures].[Count] ....but this measure is never empty it is always equal to 1. So the following without Non Empty should return exactly the same result:
WITH
MEMBER [Measures].[Count] AS 1
SELECT
[Measures].[Count] ON COLUMNS,
[Account].[Account Number].ALLMEMBERS*
{[simulationDate].[day].&[10010101]}*
{[statisticPeriod].[period].&[201201]}*
{[region].[code].&[SO]} ON ROWS
FROM [myWH];
So in terms of filtering you aren't doing any - what sort of filtering do you need? If you replace [Measures].[Count] with an actual measure from your cube and use the NON EMPTY then you should see a lot less rows:
SELECT
[Measures].[ReplaceWithActualMeasure] ON COLUMNS,
NON EMPTY
[Account].[Account Number].ALLMEMBERS*
{[simulationDate].[day].&[10010101]}*
{[statisticPeriod].[period].&[201201]}*
{[region].[code].&[SO]} ON ROWS
FROM [myWH];
In the end I ended up using the filters as my columns, and letting the NON EMPTY clause take care of the filtering:
SELECT
NON EMPTY
{[simulationDate].[day].&[10010101]} *
{[statisticPeriod].[period].&[201201]} *
{[region].[code].&[SO]}
ON COLUMNS,
NON EMPTY
[Account].[Account Number].ALLMEMBERS
ON ROWS
FROM [myWH]

MDX Query - Select Columns From Same Dimensions

I have a requirement displaying data from same dimension in more than 1 column. For eg. I want to show data Year and Month wise. In my dimension structure, Year and Month belongs to same hierarchy. When I run below query I get error. PFB the query.
Select NON EMPTY {[Measures].[Target Actual Value]} ON 0,
NON EMPTY {[Realization Date].[Hierarchy].[Year Name].Members *
[Realization Date].[Hierarchy].[Month Year]} ON 1
From [Cube_BCG_OLAP]
The error I get is Query (2, 12) The Hierarchy hierarchy is used more than once in the Crossjoin function. I am new to MDX queries. Please help in this regard. Thanks in advance.
Select NON EMPTY {[Measures].[Target Actual Value]} ON 0,
NON EMPTY {[Realization Date].[Hierarchy].[Year Name].Members ,
[Realization Date].[Hierarchy].[Month Year]} ON 1
From [Cube_BCG_OLAP]
Instead of CROSSJOIN have a set as above. In a set, you can put members from same hierarchy
I like Sourav's answer - but it will put the results in one column which is slightly different than the question.
In AdvWorks this is in one column:
SELECT
[State-Province].MEMBERS ON COLUMNS
,{
[Date].[Calendar].[Calendar Year].MEMBERS
,[Date].[Calendar].[Month].MEMBERS
} ON ROWS
FROM [Adventure Works];
It is possible to switch to two columns and use a cross join but you need to find out the details of your Date dimensions Attribute hierarchies (as opposed to User hierarchies):
SELECT
[State-Province].MEMBERS ON COLUMNS
,
[Calendar Year].[All Periods].Children
* [Month].MEMBERS ON ROWS
FROM [Adventure Works];
In your cube maybe something like this:
SELECT
NON EMPTY
{[Measures].[Target Actual Value]} ON 0
,NON EMPTY
[Year Name].MEMBERS
*
[Month Year].MEMBERS ON 1
FROM [Cube_BCG_OLAP];

Getting a count of users each day in Mondrian MDX

I'm trying to write a query to give me the total number of users for each customer per day.
Here is what I have so far, which for each customer/day combination is giving the total number of user dimension entries without splitting them up by customer/day.
WITH MEMBER [Measures].[MyUserCount]
AS COUNT(Descendants([User].CurrentMember, [User].[User Name]), INCLUDEEMPTY)
SELECT
NON EMPTY CrossJoin([Date].[Date].Members, [Customer].[Customer Name].Members) ON ROWS,
{[Measures].[MyUserCount]} on COLUMNS
FROM
[Users]
The problem with your calculated member is that [User].CurrentMember is set to the All member for every row tuple, and thus the count is the total. What you need is a way for the [Customer].CurrentMember and [Date].CurrentMember to effectively filter the [User] dimension.
You need to use a measure that makes sense, i.e. that will have a non-empty value for meaningful joins of the dimension members that you're interested in.
To find this out, you could start by running a query like this:
SELECT
NON EMPTY CrossJoin(
[User].[User Name].Members,
[Measures].[Some measuse]
) ON COLUMNS,
NON EMPTY CrossJoin(
[Date].[Date].Members,
[Customer].[Customer Name].Members
) ON ROWS
FROM [Project]
You would have selected Some measure adequately. The results of that query will be a lot of empty cells, but in a given row, the columns that do have a value correspond to the Users that are related to a given Customer x Date tuple (on the row). You want to count those columns for every row. COUNT and FILTER are what you need, then the query with the calculated member will be
WITH MEMBER [Measures].[User count] AS
COUNT(
FILTER(
[User].[User Name].Members,
NOT ISEMPTY([Measures].[Some measure])
)
)
SELECT
NON EMPTY {[Measures].[User count]} ON COLUMNS,
NON EMPTY CrossJoin(
[Date].[Date].Members,
[Customer].[Customer Name].Members
) ON ROWS
FROM [Users]
I am assuming a fair bit here, but with some experimentation you should be able to work it out.