MDX Range with non existing members - ssas

I have a MDX query where the string is parsed from a front-end application with forms. End users can restrict a query based on a free text field where they can input a range from invoice number and to invoice number. The query gets build based on this 2 parameters:
SELECT
{[Measures].[Amount]} ON COLUMNS,
NON EMPTY
(
(
[Invoices].[Invoice Number].[Invoice Number].[100000000]:[Invoices].[Invoice Number].[Invoice Number].[222222222])
) ON ROWS
FROM [MyCube]
However the range operator fails if an end user types in a non existing member. I think that I need to convert these fields somehow to a decimal number and than do the check with > and <.
I already have some ideas. However I am not able to get it to work. Here I try to just filter on numbers > 0 (If this works I can fill the the parameter for > and add one for <.
SELECT
{[Measures].[Amount]} ON COLUMNS,
(
FILTER(
[Invoices].[Invoice Number].[Invoice Number].members
, Cdec([Invoices].[Invoice Number].Currentmember.Properties("Key")) > 0
)
) ON ROWS
FROM [MyCybe]
However after 5 minutes I still have no response.. so cancelled the query.

I've calculated this way (it's for dates, but the idea is the same):
with
member [Measures].[RD_Key] as CDec([Report Date].[Report Date ID].Currentmember.Member_Key)
member [Measures].[ResultFilter] as [RD_Key]>20130801 and [RD_Key]<20131013
select {[Measures].[Count],[Measures].[RD_Key]} on 0
,Filter([Report Date].[Report Date ID].members,[Measures].[ResultFilter]) on 1
FROM [DATA]

If FILTER is slow maybe try using the HAVING clause. I'm assuming that no conversion of the Member_Key is needed as keys are usually numeric:
WITH
MEMBER [Measures].[Inv_Key] as
[Invoices].[Invoice Number].Currentmember.Member_Key
SELECT
{
[Measures].[Amount]
,[Measures].[Inv_Key]
} ON COLUMNS
,[Invoices].[Invoice Number].[Invoice Number].members
HAVING
[Measures].[Inv_Key] > 100000000
AND
[Measures].[Inv_Key] < 222222222
ON ROWS
FROM [DATA]

Related

MDX Filter based on a Dimension field and Measure field not returning expected result

I'm using SSAS 2019 and have the following MDX query to determine data errors - i.e. in this case where a given score ([Measures].[Score]) is above what the maximum score ([PerformanceLevel].[MaxScore]) is
SELECT NON EMPTY {
[Measures].[FactTestScoreCount]
} ON COLUMNS,
NON EMPTY
{(
[TestEvent].[Key].[Key].Members
)} ON ROWS
FROM [TestScore]
WHERE
(
FILTER(
[PerformanceLevel].[MaxScore].[MaxScore].Members,
[PerformanceLevel].[MaxScore].CurrentMember.MemberValue < [Measures].[Score]
)
)
...you'll note it uses a Measure value to compare against a Dimension value in the filter
However the above query incorrectly returns all rows (it should return zero rows as we have no scores in the current database that are above the maximum score)
I have tried using a HAVING and also tried to add the filter into the FROM however I get the same result. I have also tried converting the data-type to int on both sides of the expression but to no avail. I tried temporarily changing the condition to hard-code (numeric) values and this seems to narrow down the issue as being the [Measures].[Score] in the FILTER - i.e. as far as I can see putting the Measure within the FILTER doesn't seem to be working as expected but I can't work out why
Any ideas would be much appreciated
I didn't fully understand what the first parameter of the Filter function represented - specifically the granularity, otherwise it (depending on your aggregation type will SUM the measure). Also moving the Filter up to the select allows more flexibility when joining/displaying rows - so I came up with the below which works well
SELECT NON EMPTY {
[Measures].[FactTestScoreCount]
} ON COLUMNS,
Filter(
NonEmpty(
{(
[TestEvent].[Key].[Key].members
)}
), [Measures].[Score] > [PerformanceLevel.[MaxScore].CurrentMember.MemberValue
) ON ROWS
FROM [TestScore]

MDX date range with NON EMPTY clause is not slicing the data for the range

I am working to optimize the query time. But in my cases, case 1 and case 2 are returning the same result. case 1 should return result for a particular data range i.e. [time].[2015].[5].[10] : [time].[2015].[6].[9] instead it is returning only for [time].[2015].[6].[9] as the result of case 2. case 1 returns the correct result i.e. data for the range but only if you remove the non empty clause. removing the non empty clause means it will search the entire data sets which is again taking lots of time. again case 3 returns correct result but operation is even more time then the first approach. Anybody facing such issue or can guide me to for the problem.
CASE 1
WITH
MEMBER [Measures].[abc_type] AS
[abc].CurrentMember.Properties("abc_type")
MEMBER [Measures].[abc_desc] AS
[abc].CurrentMember.Properties("abc_desc")
MEMBER [Measures].[abc_class] AS
[abc].CurrentMember.Properties("abc_class")
SELECT
NON EMPTY
{
[Measures].[abc_type]
,[Measures].[abc_desc]
,[Measures].[abc_class]
} ON COLUMNS
,NON EMPTY
Filter
(
{[abc].[abc_id].MEMBERS}
,St_contains
(
[district].[district_id].[1].Properties("the_geom")
,[abc].CurrentMember.Properties("the_geom")
)
) ON ROWS
FROM [analytics_cube]
WHERE
[time].[2015].[5].[10] : [time].[2015].[6].[9];
CASE 2
WITH
MEMBER [Measures].[abc_type] AS
[abc].CurrentMember.Properties("abc_type")
MEMBER [Measures].[abc_desc] AS
[abc].CurrentMember.Properties("abc_desc")
MEMBER [Measures].[abc_class] AS
[abc].CurrentMember.Properties("abc_class")
SELECT
NON EMPTY
{
[Measures].[abc_type]
,[Measures].[abc_desc]
,[Measures].[abc_class]
} ON COLUMNS
,NON EMPTY
Filter
(
{[abc].[abc_id].MEMBERS}
,St_contains
(
[district].[district_id].[1].Properties("the_geom")
,[abc].CurrentMember.Properties("the_geom")
)
) ON ROWS
FROM [analytics_cube]
WHERE
[time].[2015].[6].[9];
CASE 3
WITH
MEMBER [Measures].[abc_type] AS
[abc].CurrentMember.Properties("abc_type")
MEMBER [Measures].[abc_desc] AS
[abc].CurrentMember.Properties("abc_desc")
MEMBER [Measures].[abc_class] AS
[abc].CurrentMember.Properties("abc_class")
MEMBER [time].[newtime] AS
Aggregate([time].[2015].[5].[10] : [time].[2015].[6].[9])
SELECT
NON EMPTY
{
[Measures].[abc_type]
,[Measures].[abc_desc]
,[Measures].[abc_class]
} ON COLUMNS
,NON EMPTY
Filter
(
{[abc].[abc_id].MEMBERS}
,St_contains
(
[district].[district_id].[1].Properties("the_geom")
,[abc].CurrentMember.Properties("the_geom")
)
) ON ROWS
FROM [analytics_cube]
WHERE
[time].[newtime];
Ranges of time are always evaluated by Mondrian as a full level scan. It will load all of the members of the given time level and will start iterating over the members until it finds the first bound. It will then create a sublist up until the last member of the range.
There is an enhancement request filed to turn ranges into SQL predicates here.
If you get a chance to test the prototype code, let us know how it works for you

Counting items with multiple criteria

I have a table (getECRs) in PowerPivot.
Right now, I've been able to create a calculated column that counts how many times the row's customer ID (BAN) occurs in the BAN column with the following formula:
=CALCULATE(COUNTROWS(getECRs),ALLEXCEPT(getECRs,getECRs[BAN]))
What I'm having difficulty with is adding multiple criteria to the CALCULATE formula in PowerPivot.
Each row has a column that gives the date the request was generated _CreateDateKey. I'm trying to include criteria that would only include multiple BANs if they fall within 7 days (before or after) the _CreateDateKey for the row.
For example for one BAN, there are the following dates and their expected counts:
_CreateDateKey Count Explanation
6/13/2014 3 Does not include 6/23
6/13/2014 3 Does not include 6/23
6/16/2014 4 Includes all
6/23/2014 2 Does not include the 2 items from 6/13
In Excel I would use a COUNTIFS statement, like below to get the desired result (using table structure naming)
=COUNTIFS([BAN],[#BAN],[_CreateDateKey],">="&[#[_CreateDateKey]]-7,[_CreateDateKey],"<="&[#[_CreateDateKey]]+7)
But I can't seem to figure out the relative criteria needed for the dates. I tried the following as a criteria to the CALCULATE function, but it resulted in an error:
getECRs[_CreateDateKey]>=[_CreateDateKey]-7
Error: Column '_CreateDateKey' cannot be found or may not be used in this expression.
This formula answers your specific question. It's a good pattern to get down as it's highly re-usable - the EARLIER() is referencing the value of the current row (slightly more complex than this but that is the end result):
=
CALCULATE (
COUNTROWS ( getECRs ),
FILTER (
getECRs,
getECRs[BAN] = EARLIER ( getECRs[BAN] )
&& getECRs[_CreateDateKey]
>= EARLIER ( getECRs[_CreateDateKey] ) - 7
&& getECRs[_CreateDateKey]
<= EARLIER ( getECRs[_CreateDateKey] ) + 7
)
)
Fundamentally you should probably be looking to get away from the 'Excel mindset' of using a calculated column and deal with this using a measure.
An adaptation of the above would look like this - it would use the filter context of the PIVOT in which you were using it (e.g. if BAN was rows then you would get the count for that BAN).
You may need to adjust the ALL() if is too 'open' for your real world context and you might have to deal with totals using HASONEVALUE():
=
CALCULATE (
COUNTROWS ( getECRs ),
FILTER (
ALL(getECRs),
getECRs[_CreateDateKey] >= MAX ( getECRs[_CreateDateKey] ) - 7 &&
getECRs[_CreateDateKey] <= MAX ( getECRs[_CreateDateKey] ) + 7
)
)

MDX - Is it possible to have two unrelated dimension members in one row?

I need to create the table of the following structure in MDX (to be used in SSRS report):
For that I have 2 dimensions and one measure:
Option dimension, with option type and option value attributes
Standard dimension, with IsStandard flag
Price measure
In first column I need to show all option type attributes,
in second all value attributes where IsStandard flag is set to [Y],
in third values chosen by user in parameters and
in fourth prices for components selected by user.
Is it possible to do the above in single MDX? Or will I be better off creating 2 distinct queries and creating 2 tables for them?
EDIT: Since my updates won't fit into the comment, I will add some thoughts here.
EXISTS function from answer below does not filter the result set, I don't get standard values but all possible values concatenated. When I issue the following code:
SELECT
[Measures].[Price] ON 0,
NON EMPTY [Option].[Option Type].children
*
[Option].[Option Value].children ON 1
FROM [Cube]
WHERE
(
[Standard].[IsStandard].&[Y],
[Configurations].[Configuration].&[conf1]
)
It returns the default values correctly, but if I use
SELECT
[Measures].[Price] ON 0,
[Option].[Option Type].children
*
EXISTS(
[Option].[Option Value].[Option Value].members
,([Standard].[IsStandard].&[Y],[Configurations].[Configuration].&[conf1])
) ON 1
FROM [Cube]
It does not filter the results.
If you can accept a slightly different order of columns, then this can be done in MDX, using a calculated measure which is actually a string (as you want to see a list of attributes values in column). This avoids having the same attribute twice in the rows:
WITH Member Measures.[Standard Value] AS
Generate(NonEmpty([Option].[Option Type].[Option Type].Members,
{([Standard].[IsStandard].&[Y],
Measure‌​s.[Price]
)}
),
[Option].[Option value].CurrentMember.Name,
", "
)
SELECT { Measures.[Standard Value], Measures.[Price] }
ON COLUMNS,
NON EMPTY
[Option].[Option Type].[Option Type].Members
*
{ #chosenValues } // the parameters value should be a comma separated list like "[Option].[Option value].[AMD], [Option].[Option value].[INTEL]"
ON ROWS
FROM [Your Cube]
WHERE [Configurations].[Configuration].&[conf1]
You can adapt the list separator (the last argument of the Generate function) to anything you like.
And in case there is more than one measure group that is related to the dimensions [Option], [Standard], and [Configurations], you should add the name of the measure group to use for determining the relationship as additional last parameter to the Exists, so that you and not the engine determines that. Just use the name of the measure group in either single or double quotes.
Yes it is, dimension will just be ignored. This is assuming you've all in the same schema / cube.
Note, depending on the OLAP Server you're using it's possible you've to change a flag that sends an error if you're using a dimensions that is not defined at Measure Group level.

filter in a mdx query is not correctly applied

I have a MDX Filter problem, which I think I use correctly however I still get some rows which I don't want to get.
Sample query is :
SELECT {[Measures].[AFR],[Measures].[IB],[Measures].[IC All]} ON COLUMNS,
NON EMPTY ( ([dim_ProductModel].[Product Model].&[DSDB])
* FILTER( ([dim_Country].[Country Name].members -[dim_Name].[Country Key].[All]),[Dim_Date].[Date Full].&[2014-01-01]*[Measures].[IB] > 0 AND NOT ISEMPTY ([Dim_Date].[Date Full].&[2014-01-01]*[Measures].[IB] ))
* {[Dim_Date].[Date Full].&[2013-02-01]:[Dim_Date].[Date Full].&[2014-01-01]})
ON ROWS FROM [cub_dashboard_spares]
Now what I need, is to exclude those countries! (Filter) for particular product model [DSDB] in this case , where in january 2014 (dimension) the measure IB was > 0 or not null. Now it seems that it filters out correctly some countries however I still get some results, where either IB is 0 in last month OR IB is (null) in last month (January 2014 in our case).
Could please anybody help me where can be the problem?
Thank you very much
I would add the country to the filter condition, i. e. use
SELECT {[Measures].[AFR],[Measures].[IB],[Measures].[IC All]}
ON COLUMNS,
NON EMPTY
[dim_ProductModel].[Product Model].&[DSDB]
* FILTER(([dim_Country].[Country Name].members -[dim_Name].[Country Key].[All]),
([dim_Country].[Country Name].CurrentMember, [Dim_Date].[Date Full].&[2014-01-01], [Measures].[IB]) > 0
AND NOT
ISEMPTY(([dim_Country].[Country Name].CurrentMember, [Dim_Date].[Date Full].&[2014-01-01], [Measures].[IB]))
)
* {[Dim_Date].[Date Full].&[2013-02-01]:[Dim_Date].[Date Full].&[2014-01-01]}
ON ROWS
FROM [cub_dashboard_spares]
this is my problem..: don't understand why the results with AFR 0 appear :(