MDX: Filter a member that doesn't exist? - mdx

I'm new to MDX, so I assume this is a newbie question.
Existing dimension: status
Existing Measure: count
Existing Query:
SELECT
NON EMPTY [status].CHILDREN ON 0,
NON EMPTY Measures.count ON 1
FROM [objects]
I want count the records with status='C'. But sometimes, there're no records that match that criteria. So if I do:
SELECT
NON EMPTY [status].[C] ON 0,
NON EMPTY Measures.count ON 1
FROM [objects]
I get this error:
*MDX object '[status].[C]' not found in cube 'objects'*
I would like a query that returns 0 in that case. Which is the right way to do that query?
Thanks!

I assume from your question that you don't actually have a Status dimension table in your datasource. Instead, you have a dimension defined that is using a column in the Fact table. This works great, but it doesn't allow you to define a fixed set of members for that dimension...you're basically stuck with the facts that you have.
The solution, the way I see it, would be to create a separate table called DimStatus, and pre-populate it with all of the valid statuses that might be used by your facts, and have the fact table reference the Status dimension table.
Then things will work the way you want them to. You can automatically hide unused members, or you can include all of them, or a set of just the ones you want.
One caveat is that it will show (null) instead of 0 if there are no matching facts. You can get around this with a simple IIF(ISEMPTY()):
WITH MEMBER
[ZeroCount] AS
IIF(ISEMPTY([Measures].[Count]), 0, [Measures].[Count])
SELECT [ZeroCount] ON COLUMNS,
[Status].Members on ROWS
FROM [MyCube]
This will show all statuses and either the count, or a zero. Unfortunately it requires changes to your data source and cube, so hopefully that's an option for you.
I played with some queries and I don't think it's possible to do this more easily. You can't create a set with invalid members--that would create invalid tuples, and nothing would work properly. I also tried the "hack," and didn't get it to work as expected.

The best idea, which is what most client applications do, is to query the metadata to find out what members exist in a dimension and then only issue queries for members that exist.
The following article lists the various ways of getting at dimension metadata link text
the other "hack" might be to do the following:
SELECT
NON EMPTY StrToSet("[status].[C]") ON 0,
NON EMPTY Measures.count ON 1
FROM [objects]
But that will still not give you a 0, instead it will give you cell set with no columns. And it's not really an approach that I would recommend.

The solution is to use dynamic sets (CREATE DYNAMIC SET). These are evaluated based on user permissions.
WITH DYNAMICS SET [MySet] {[status].[C]}
SELECT
NON EMPTY [MySet] ON 0,
NON EMPTY Measures.count ON 1
FROM [objects]
But as stated above, this solves only filtration, still you miss any member o axis 0 to display.

Related

MDX Calculated Member filter using attribute not working

I have this setup:
ID T Date
2 T2 2022-11-18
3 T1 2022-11-21
and in the main fact table there are deals with ID 2 and 3.
Date is an attribute and appears, and works correctly, as a slicer in a pivot table in Excel. T is also an attribute, not visible, purely for the calculated members.
I created a Calculated Member and it doesn't work:
([Date].[T].&[T2], [Measures].[Notional_SUM])
However a check/test using ID does:
([Date].[ID].&[2], [Measures].[Notional_SUM])
obviously this works as 2 is actually in the fact table but what have I forgotten such that using T does not work?
I want to be able to use T as there'll always be T1 and T2 dates but I may not always know the ID (auto- generated by the SQL script rolling the dates).
***EDIT - After testing in Excel I realised that the one I thought does not work actually does if Date is removed from the slicer/top setup.
So obviously the top/slicer is a WHERE on just that date meaning my calculated member
([Date].[T].&[T2], [Measures].[Notional_SUM])
does not 'find' any T2 in the data it sees.
So how can I have a Calculated Member that always shows the T2 data?
I'm constructing an SSAS copy of an existing in-memory Java OLAP cube which does this and I have to ensure all dims/measures are the same.
Thanks
Leigh
tilleytech.com
it has been long long time since I wrote MDX, and as I do not have a running SSAS to debug your issue, I will try to dig the answer from my memory.
There is a difference between the use of &, which I believe is to be used on keys, and not on members. Try to use this:
([Date].[T].[T2], [Measures].[Notional_SUM])
So actually as I've not used SSAS before I'm still learning bits and I had not checked out the attribute relationship tab.
I used the attribute relationship tab to define that T is related to Date and not ID (the ID links to the fact tables).
Once this was done the behaviour now works and when Date is changed the T2 values, and move/diff calculated members, all work as expected.

MDX multiple conditions filter on multiple dimensions

I am relatively new to MDX, about a month or so, and I am now writing MDX queries against a remote cube I also work on (Java 8 ActivePivot).
This query works when they are ORs, but when I add parentheses and change that first OR to an AND it works, kind of, but drops the measure resulting in the CDR and BOOK dimensions coming back correctly. Can someone with more MDX knowledge tell me what I have missed or do not yet know?
WITH
Member [Measures].[CDR_Label] AS [CDR].[CDR].CURRENTMEMBER.MEMBER_CAPTION
Member [Measures].[Book_Label] AS [Book].[Book].CURRENTMEMBER.MEMBER_CAPTION
SELECT
NON EMPTY
{[Measures].[CDR_Label],
[Measures].[Book_Label],[Measures].[RepoRate.LATEST]}
ON COLUMNS,
NON EMPTY
FILTER(
([CDR].CHILDREN,[Book].CHILDREN), (LEFT([CDR].[CDR].CURRENTMEMBER.MEMBER_CAPTION,1) = "8") AND
(LEFT([Book].[Book].CURRENTMEMBER.MEMBER_CAPTION,2) = "ST" OR
RIGHT([Book].[Book].CURRENTMEMBER.MEMBER_CAPTION,4) = "CIES"))
ON ROWS
FROM [TraderCube]
WHERE ([Date].[Date].[2019-10-23])
And here the query before I changed it, with OR OR etc which works. I wanted the above to return only the CDR beginning with 8, which it does, but it loses the measure (and also breaks my headers - as this is actually being fired from inside an xll / custom Excel function, to a dll calling the remote cube using AdomdClient package as I am building a very custom plugin - Essentially the ability for users to use simple words/from enumerations presented and I then translate and construct MDX in C# to fire at the cube. Data comes back and I send 2D arrays back to Excel :)).
WITH
Member [Measures].[CDR_Label] AS [CDR].[CDR].CURRENTMEMBER.MEMBER_CAPTION
Member [Measures].[Book_Label] AS [Book].[Book].CURRENTMEMBER.MEMBER_CAPTION SELECT NON EMPTY {[Measures].[CDR_Label],[Measures].[Book_Label],[Measures].[RepoRate.LATEST]}
ON COLUMNS,
NON EMPTY
FILTER(
([CDR].CHILDREN,[Book].CHILDREN),
LEFT([CDR].[CDR].CURRENTMEMBER.MEMBER_CAPTION,1) = "8" OR
LEFT([Book].[Book].CURRENTMEMBER.MEMBER_CAPTION,2) = "ST" OR
RIGHT([Book].[Book].CURRENTMEMBER.MEMBER_CAPTION,4) = "CIES")
ON ROWS
FROM [TraderCube]
WHERE ([Date].[Date].[2019-10-23])
Aah...ignore me!
I think I was tired and didn't see the pattern. Essentially, and I just reproduced this, if you ask for two dimension patterns that do exist with a measure, you get back the dimensions you expect (in my case 3, a real measure and two fake / labels for the dimensions to bring them all back as rows).
If there are no matches it seems to return you back what you asked for without any measures as they do not exist for the dimension combination.

Showing measure values as "not applicable" which are not related to dimensions

I have a requirement where report should show measures as "not applicable" if one selects a attribute which is not linked to that measure Group.
1) unrelateddimesnion= 'false' is not solving my problem because i have few default members.
2) I could able to show measure value as "not applicable " by Writing this MDX statement
([Customer].[customer name].[customer name], [measures].[sales forecast]) = 'not applicable'
but with this i have to repeat the same line for each and every attribute present in the dimension ( and also for each and every measure present in the measure Group)
can someone help me Writing the MDX for entire dimension instead for individual attribute. Thanks in advance.
Kind Regards
Mah
Bad news! An MDX script on your cube can't reference such a sub-cube in a simple way. You may have seen the LEAVES(dimension) function for a scope statement but that won't work when one attribute in a dimension has the [All] level and another has a selection. (That is to say the function returns the leaves of the dimension's key attribute). What you can do is use nested scope statements with the outer one filtering down to the list of measures you want to affect. That will at least save you typing a formula num_attributes * num_measures times. The scope statement may even accept the MEASUREGROUPMEASURES function. (When I last used that it only returned visible measures but that's probably what you want anyway.)
It may be easier to link measure group and dimension and let your data sit on the UNKNOWN member. (Or an explicit dummy member.) Then filters against or slices to real customer hierarchy values will exclude your [Sales Forecast] rows and show it as null. That's not something I've done and it'll have ramifications for error processing and you'll have to allow users sight of the unknown or dummy member. So recommend you play with the idea before you rely on it.
I hope this helps some.

How to get a count of Distinct Dimension values in an SSAS MDX Query

I am trying to write an MDX query to return some information about survey questions. I want Average response and total responses in my results. I have two types of questions. One type of question has a single response. Another type of question can have multiple responses (Pick all that apply). Each question is tied to a question ID and a respondent ID. The following query works (somewhat)
Select NON EMPTY
{
[Measures].[Average Response], [Measures].[Total Count]
} ON 0
, NON EMPTY
{
([Question].[Question ID].[Question ID].ALLMEMBERS)
} ON 1
From [Cube]
Average Response is a combination from both single responses and multiple responses (two different fact tables). The total count is also a combination of the two tables. The problem is that for single response questions, I can just count the number of respondents. For multi response questions that falls down as I can have way more responses than I do people taking the survey. I really want to know how many people provided an answer. To do this, I think I need the distinct count of respondent IDs. So I tried changing my first axis to this.
[Measures].[Average Response], [Measures].[Total Count], DISTINCTCOUNT([Respondent].[Respondent ID])
Well, that doesn't work and I really didn't expect it to. I got "The function expects a tuple set expression for the 3 argument. A string or numeric expression was used." which is rapidly becoming my favorite SSAS error message. I am still green at this and I guess I am still thinking SQL. How can I get an average of the responses and a count of the distinct Dimension values in the same query. BTW, my query does have a slicer and I could provide that if needed but I don't think it relevant as I get the same problems with or without the slicer.
When working with the MDX DistinctCount function, it returns the count of distinct, non-empty tuples of a given set of data. Perhaps try doing something like
DistinctCount({[Respondent].[Respondent ID].members * [Measures].[Total Count]})
so that way you are working with a set (e.g. {...}) of data.
If you're working with a larger set of data, you may want to consider creating a Distinct Count measure. The DistinctCount function itself is a SSAS Formula Engine query while using the Distinct Count measure would allow Analysis Services to use both the Storage Engine and Formula Engine. For more information, please refer to Analysis Services Distinct Count Optimization.

MDX Calculated Member SubCube

I am relatively new to this depth of MDX, but here is my dilemma. My goal is to implement a calculated member using a .Net Stored Procedure. The calculation (XIRR) will be based on a set of cash flow dates and cash flow amounts. Ideally this would be a calculation in my cube that is available as a measure to Excel/Browser users.
So to start simple I am just trying to implement my own COUNT calculated member/measure (not even using .Net) to say count the # of members in a given dimensions based on the current context. So lets say I have a dimensions Customer with a Customer Id Key. And let's say there are a total of 100 customers in my database. So Count(Customer.CustomerId.AllMembers) would be 100. Now when you start using the browser and say filter on Customer.CustomerId.&1, Customer.CustomerId.&2 (customer id 1 and 2) I would expect my count calculated member to return 2 but it returns the total 100 count. I have tried using exists. I am sure there is something that I am just fundamentally not understanding yet.
Hopefully this makes sense, would hugely appreciate any help from someone that has a good understanding of SSAS/MDX and calculations. Thanks in advance.
Marty
You may have some issues here, I did when I tried to do a similar thing.
Your calculated member is not honouring the client sub-select, which is normal. What in theory you would do is create a dynamic set, and then use that in the calculated member to force the dimension count to be evaluated in the context of the subcube your filters have created. Mosha has a good article here: http://sqlblog.com/blogs/mosha/archive/2007/08/25/mdx-in-katmai-dynamic-named-sets.aspx
So you'd end up with something like:
CREATE DYNAMIC SET CurrentCube.Customers AS
EXISTING(Customer.CustomerId.CHILDREN);
CREATE MEMBER CurrentCube.Measures.CustomerCount AS
Customers.COUNT
Now the real problem you'll have is a bug in SSAS https://connect.microsoft.com/SQLServer/feedback/details/484865/calcuated-member-with-a-reference-to-dynamic-named-set-kills-the-cubes-performance so the code above, which will probably work just fine locally, will kill a production cube. This was an exciting learning experience for me.
See if you can get any of the workarounds to work, I couldn't.
I was able to get what I wanted, but I had to create query-scoped dynamic sets as part of the MDX query, I wasn't able to create it as a cube object:
WITH DYNAMIC SET Customers AS
EXISTING(Customer.CustomerId.CHILDREN);
MEMBER Measures.CustomerCount AS
Customers.COUNT
SELECT
Measures.CustomerCount
ON COLUMNS
FROM [Cube]
WHERE Customer.CustomerId.&[1]
Let us know how you get on.