Mondrian MDX Number of elements that match a condition - mdx

I'm trying to get the number of facts that match a condition.
My desired output: the number of ratings that are bigger than 3.
What I actually get: the total number of user ratings in case that the average of the ratings is over 3.
This is my query:
With Member [Measures].[Number of possitive ratings] as
IIF(
[Measures].[User Rating] > 3,
[Measures].[Number of Users Rating],
0)
SELECT NON EMPTY
[Measures].[Number of possitive ratings] ON COLUMNS,
[Movie Year].[All Years] ON ROWS
FROM
[Rating]
When I replace [Measures].[Number of Users Rating] for 1, then I get 1 in case the average is over 3.
I don't like the idea of creating a new measure in the cube just for this.

Related

Number or Results and WITH MEMBER Calculation interacting weird

In our MDX Queries, we use a template like the following WITH MEMBER . SELECT SUBSET . FROM (SELECT . FROM .) a lot.
What this particular query should do (and does!) is list all product variants matching a filter, and give the sales amount for it for a month in time. On the same row, we have the sales total of all variants of this product.
We need only a subset of the result (for paging), and the results need to ordered to allow paging of course. Then there is a non empty, so only product variants that were sold in the time period qualify.
This works just fine. Paging also works: putting 30, 60, 90 for Start in SUBSET is gives the correct results.
However, if I put a 1 as Count (SUBSET(..., x, 1)) the result of the "Price all" goes to (null) for each and any row I select with x. If I return two or more rows it works just fine, and all rows have their correct values.
Two results and the correct value in the rightmost column (in case you are wondering how the total of all variants, 67, can be lower than the sales of one particular variant (280): I picked a bad example - there was a return (so a negative sale) for another variant of this product, for 213. The 67 is correct and desired!)
One Row and a (null) result
I do not understand how or why the SUBSET count would interfere with the Tuple I select in the WITH MEMBER. If it does it for 30 rows at a time, why not for one?
*edit
I just tried, what would happen if I filter in a way that only one result matches (and SUBSET paging is set to "working values" of 0, 30): The same as in the 2nd screenshot, for one result row the WITH MEMBER evaluates to (null).
So it is not that SUBSET is the problem, but more general: When there is only one result row!
Could this be a bug in our SQL Server Version? It is SQL 2012 with SP4 and all latest security patches.
WITH
MEMBER [DIM Date].[HI Year_Month_Day].[CURRENT_MONTH] AS
[DIM Date].[HI Year_Month_Day].&[20201215].Parent /* Select Month of December */
MEMBER [MEASURES].[Price all] AS (
(
[DIM Products].[HI Products].Currentmember.Parent
, [DIM Products].[HI Subproduct].[Total]
)
, [MEASURES].[Price]
), FORMAT_STRING = '#,0' /* Get the parent product total next to every subproduct */
SELECT {
([DIM Datum].[HI Year_Month_Day].[CURRENT_MONTH], [MEASURES].[Price])
, ([DIM Datum].[HI Year_Month_Day].[CURRENT_MONTH], [MEASURES].[Price All])
} ON COLUMNS
, {
SUBSET(
ORDER(
NONEMPTY(
([DIM Products].[HI Produt Subproduct].[Subproduct])
, {([DIM Date].[HI Year_Month_Day].[CURRENT_MONTH], [MEASURES].[Price])}
)
, ([DIM Date].[HI Year_Month_Day].[CURRENT_MONTH], [MEASURES].[Price])
, BDESC
)
, 0
, 30
)
} ON ROWS
FROM (
SELECT
{[DIM StoreLocation].[HI Country].[Country].&[US]}
* {[DIM Productgroup].[HI Productgroup].[Productgroup].&[Bikes]}
ON COLUMNS
FROM [Cube]
)

MDX - Top N elements of every subgroup

Let's assume I have a cube with a sales fact table and 3 dimensions: Time (with hierarchy year-month-day), Geography (with hierarchy continent-country-region) and Product with some characteristics about the product sold, let's take the brand for instance.
What I am trying to do is to display the top N brands with respect to the measure chosen, in this case average sales (which is already in the cube as total sales/number of products sold), for every region and month.
I also need to display the country and the year, for clearness.
I have searched for the solution to this everywhere, I came close to it but not completely. I hope someone can help me figure it out.
So I used generate and topcount with the following query, but the problem is that the topcount calculates the N best selling brands over the whole dataset, not for every region and month subgroup. And then applies this top N to every subgroup.
WITH SET [Top N Brands] AS
Generate([Geography].[Region].Children,
TopCount(Geography].[Region].CurrentMember * [Gpu Product].[Brand].[Brand].MEMBERS,
5, ([Measures].[averageSales])))
SELECT {[Measures].[averageSales]} ON COLUMNS,
NON EMPTY ( [Time].[Year].[Year],
[Time].[Month].[Month],
[Geography].[Country].[Country],
[Top N Brands]) ON ROWS
FROM [Cube]
So I am getting this, with the global top 5 brands distributed over the regions, if sold there:
But I should get this with different top 5s for every region:
What am I missing?
You need to use rank. Take a look at the example below. I am using the sample Adventure Works Db, here I am listing For each country, for each product category in that country, the top three subcategories according to internet sales.
WITH
MEMBER [Measures].[Internet Sales Amount Rank] AS
RANK( ([Customer].[Country].currentmember,[Product].[Category].currentmember,[Product].[Subcategory].CurrentMember),
ORDER( ([Customer].[Country].currentmember,[Product].[Category].currentmember,[Product].[Subcategory].[Subcategory].Members) , [Measures].[Internet Sales Amount], BDESC)
)
select
non empty
([Measures].[Internet Sales Amount])
on columns
,
non empty
([Customer].[Country].[Country],
[Product].[Category].[Category],
filter([Product].[Subcategory].[Subcategory],[Measures].[Internet Sales Amount Rank]<4))
on rows
from [Adventure Works]
Result

Count dimension member based on other dimension

I would like to define a measure that will count dimension members by other dimension and add it as a measure on the cube.
Should I create a new measure group with a count of the attribute of dimension or it's better to create a calculated member?
Example on adventureworks: count products by ProductCategory
WITH
MEMBER [Measures].[Number of Products] AS
Count(Existing
[Product].[Product].[Product].Members
)
SELECT
[Measures].[Number of Products] on 0,
{[Product].[Category].Members} ON ROWS
FROM [Adventure Works]
You haven't given details, but my guess is that your current code will return the count of all products, repeated for each Product Category.
I don't have a working copy of Adventureworks to hand, but if Product is a level one level below Product Category in hierarchy "ProductHierarchy" on the Product dimension, this should work:
WITH MEMBER [Measures].[Number of Products] AS
Count([Product].[ProductHierarchy].CurrentMember.Descendants)
SELECT
[Measures].[Number of Products] ON 0,
{[Product].[Category].Members} ON 1
FROM [Adventure WOrks]

How to filter a measure based on another measure

I have a dimension table called DimUser that has 1 row per user. I have a measure based on this dimension called "USER COUNT" which is count of rows of the DimUser table. I also have a calculated measure called "ACTIVE DAYS" which returns no of days a user is active.
Now, I want to create another calculated measure based on this 2 measures, where I count only users who are active more than 5 days. I have total 5 users in my user table and 2 users in my fact table who are active more than 5 days. My MDX expression should return 2.
This is what I wrote
FILTER([Measures].[USER COUNT], [Measures].[ACTIVE DAYS] > 5)
But this gives me 5 as the answer instead of 2. What am I doing wrong?
Next I tried this, but this fails compilation saying two measures in the expression are not allowed
([Measures].[USER COUNT], [Measures].[ACTIVE DAYS] > 5)
Next, I tried creating a new calculated member called [IsActive] that returns true or false if active days > 5 and then use that as filter on the [Measures].[USER COUNT].
How do I go about doing this?
First of all, I don't think it is even possible to filter one measure on another measure, because measures are numeric values, not a set. The concept of filtering applies to a set. So filtering a measure based on another measure is absurd. What can be done though, in terms of MDX, is to create a set of users with the first filter applied(i.e. [Measures].[ACTIVE DAYS] > 5) and then getting a COUNT out of it.
Something like this(NOT TESTED):
WITH SET [ActiveUsersMoreThan5Days] AS
FILTER([User].[UserId].CHILDREN, [Measures].[ACTIVE DAYS] > 5)
//Assuming the User dimension and hierarchy here..
//Fill it in with actual..
MEMBER [Measures].CountActiveUsersMoreThan5Days AS
COUNT(NONEMPTY([ActiveUsersMoreThan5Days], [Measures].[<<Some other measure>>]))
SELECT [Measures].CountActiveUsersMoreThan5Days on 0
//,[Dimension].Hierarchy.CHILDREN ON 1
FROM [Cube]
To avoid using Filter which is iterative and not the best performing function. Also to create a measure that is context aware then the following might help:
WITH
MEMBER [Measures].[CntUsersActive5DaysOrMore] AS
Sum
(
[UserId].[UserId] //<<< or [UserId].[UserId].[UserId]
,IIF
(
[Measures].[ACTIVE DAYS] > 5
,1
,0
)
)
SELECT
[Measures].[CntUsersActive5DaysOrMore] ON 0
FROM [YourCube];

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.