MDX query dynamic where clause - sql

SELECT NON EMPTY { [Measures].[Total Value],[Measures].[Value less than 30],
[Measures].[Value less than 60],[Measures].[Value less than 90],[Measures].[Value less than 150],
[Measures].[Value less than 180],[Measures].[Value less than 365],[Measures].[Value more than 365]}
DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON COLUMNS,
NON EMPTY {[Combined].[Drill Down Path 4].[Supplier Name].ALLMEMBERS }
DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS FROM [InventoryAge]
WHERE ( [Calendar].[Report Days].[All Members].&[All].&[WantInReport].&[2].&[20141031] )
for the where clause I want to get the last element of my calender dimension. The calender dimension is as follows
What is the best way to achieve this

Try something like this:
WHERE ( [Calendar].[Report Days].[All Members].[All].[WantInReport].[Last Days].LastChild )
You should be able to use the name of your members (but with removing & in front of them), that's why .&[WantInReport]. become .&[WantInReport]..
I'd rather use .[Last Days]. than .&[2]., easier to understand when you look later at the query.
Finally using .LastChild gives you last item of your selected branch.

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 Result Count

I am a beginner in MDX queries. Can any one tell me how to get the record count that is a result of a MDX query?
The query is following:
select {[Measures].[Employee Department History Count],[Measures].[Rate]} on columns, Non Empty{{Filter([Shift].[Shift ID].[Shift ID].Members, ([Shift].[Shift ID].CurrentMember.name <> "1"))}*{[Employee].[Business Entity ID].[Business Entity ID].Members}} on rows from [Adventure Works2012].
I have tried various methods and I haven't really got a solution for that.
I assume you mean row count when you talk of "record count", as MDX does not know a concept of records, but the result shown from an MDX query is the space built by the tuples on the axes.
I see two possibilities to get the row count:
Just count the rows returned from your above query in the tool from which you call the MDX query.
If you want to count in MDX, then let's state what you want to have:
You want to know the number of members of the set of non empty combinations of [Shift ID]s and [Business Entity ID]s where the Shift ID is not "1" and at least one of the measures [Employee Department History Count] and [Rate] is not null.
To state that different: Let's call the tuples like above for which the first measure is not null "SET1", and the tuples like above for which teh second measure is not null "SET2". Then you you want to know the count of the the tuples which are contained in one of these sets (or in both).
To achieve this, we define these two sets and then a calculated menber (a new measure in our case) containing this calculation in its definition, and then use this calculated member in the select clause to show it:
WITH
SET SET1 AS
NonEmpty({{Filter([Shift].[Shift ID].[Shift ID].Members,
([Shift].[Shift ID].CurrentMember.name <> "1"))}
* {[Employee].[Business Entity ID].[Business Entity ID].Members}},
{[Measures].[Employee Department History Count])
SET SET2 AS
NonEmpty({{Filter([Shift].[Shift ID].[Shift ID].Members,
([Shift].[Shift ID].CurrentMember.name <> "1"))}
* {[Employee].[Business Entity ID].[Business Entity ID].Members}},
{[Measures].[Rate])
MEMBER [Measures].[MyCalculation] AS
COUNT(SET1 + SET 2)
SELECT [Measures].[MyCalculation] ON COLUMNS
FROM [Adventure Works2012]
Please note:
The sets SET1 and SET2 are not absolutely necessary, you could also put the whole calculation in one long and complicated definition of the MyCalculation measure, but splitting it up makes is easier to read. However, the definition of a new member is necessary, as in MDX you can only put members on axes (rows, columns, ...). These members can either already been defined in the cube, or you have to define them in the WITH clause of your query. There is no such thing as putting expressions/calculations on axes in MDX, only members.
The + for sets is a union which removes duplicates, hence this operation gives us the tuples which have an non empty value for at least one of the measures. Alternatively, you could have used the Union function equivalently to the +.
The Nonempty() I used in the definitions of the sets is the NonEmpty function, which is slightly different from the NON EMPTY keyword that you can use on the axes. We use one of the measures as second argument to this function in both set definitions.
I have currently no working SSAS installation available to test my statement, hence there might be a minor error or typo in my above statement, but the idea should work.

Show items with no data on rows | SSAS , MDX

Working on a task that required to bring all a dimension’s data to the Pivot Table(Excel Sheet) even if they are not related to the fact.
first I was able to do it by using the option “PivotTable Options” -> “Display” -> “Show items with no data on rows” from Excel. The problem here is that using this option is going to affect the other dimensions and the requirement is to only this work for the Student dimension only and the user doesn’t like to keep changing the option back every time. then I found this solution using SCOPE, below, but just like above I could not find an away to just have the scope ignore the logic if any other dimension added so the data does not get duplicated.
SCOPE ([Program].[Program Hierarchy].MEMBERS, [Measures].[Number of Students]);
THIS = IIF(ISEMPTY([Measures].[Number of Students]), 0, ([Measures].[Number of Students]));
END SCOPE;
So is there something that I can add the SCOPE above to just work in the program dimension and get ignore/ skip and work as normal if any other dimension added to the pivot table?
Any suggestion will be appreciated.
Lets suppose that for Dimension1 ,attribute1, and the attribute "Value 1", you had nothing in Fact, so this is removed from the result, now you forced Excel to display it by selecting the option. When you add another dimension's attribute lets say Dimension2.Attribute1, since "Value 1" had nothing in Fact, therefore Cube will not understand which value of of Dimension2.Attribute1 is to be displayed in front of Dimension1.Attribute1, therefore it will display all its values. So if we have 3 values in Dimension2, attribute 1 then "Value 1" will be repeated three times. Now with Excel you cannot solve the issue, however it might just be possible to write an MDX query that works.
Edit: Query Added.
The below sample query is based on AdventureWorks, the first sample shows that the result has some nulls, if i un-comment the "non-empty" all null values will vanish, go ahead try it.
select [Measures].[Internet Sales Amount] on columns,
--non empty
[Product].[Subcategory].[Subcategory]
on rows
from
[Adventure Works]
Result without non empty
Now lets add another dimension to the query. Notice that the null value for the first row(Bib-shorts) is now repeated for all values of the second dimension, Since cube has no way to determine which value to display.
select [Measures].[Internet Sales Amount] on columns,
--non empty
([Product].[Subcategory].[Subcategory],[Date].[Calendar Quarter of Year].[Calendar Quarter of Year])
on rows
from
[Adventure Works]
Result
Now the above result shows the issue you are facing. What we now need to do is whenever there is a null value we dont need the individual members of the second dimension, rather a place holder to satisfy the tuple, will work.
In the query below I have two tuples
1) for the not null data-points. Here we display the actual member of the second dimension.
2) for the null data-points, here we use ".defaultmember" which basically means that the second dimension will behave as it was never selected. Have a close look at the second dimension it says "All Period"
select [Measures].[Internet Sales Amount] on columns,
--non empty
{filter(([Product].[Subcategory].[Subcategory],[Date].[Calendar Quarter of Year].[Calendar Quarter of Year]),[Measures].[Internet Sales Amount]>0),
filter(([Product].[Subcategory].[Subcategory],[Date].[Calendar Quarter of Year].defaultmember),[Measures].[Internet Sales Amount]=null)
}
on rows
from
[Adventure Works]
Result:

Cross join same hierarchy columns

I have a SQL data cube with following hierarchy
I want to cross join Warehouse division and Code warehouse Desc. I wrote a MDX as follows
SELECT NON EMPTY
{ [Measures].[Total Value]}
DIMENSION PROPERTIES CHILDREN_CARDINALITY,
PARENT_UNIQUE_NAME ON COLUMNS,
NON EMPTY
{
[Combined].[Drill Down Path 4].[Warehouse Division].MEMBERS* [Combined].[Drill Down Path 4].[Code Warehouse Desc].MEMBERS
}
DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS FROM [InventoryAge]
WHERE ( [Calendar].[Report Days].[All Members].&[All].&[WantInReport].& [2].&[20141031] )
It gives me an error as follows
Query (13, 8) The Drill Down Path 4 hierarchy is used more than once in the Crossjoin function.
Can any body suggests a better way to do this
Please find the calender hierarchy
You don't need to crossjoin hierarchy (this is impossible) to do what you need. Just query the lowest level of it, you will get all parents also
SELECT NON EMPTY
{ [Measures].[Total Value]}
DIMENSION PROPERTIES CHILDREN_CARDINALITY,
PARENT_UNIQUE_NAME ON COLUMNS,
NON EMPTY
{
[Combined].[Drill Down Path 4].[Code Warehouse Desc].allMEMBERS
}
DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS FROM [InventoryAge]
WHERE ( [Calendar].[Report Days].[All Members].&[All].&[WantInReport].& [2].&[20141031] )
PS. You might not be able to see them in SSMS query result viewer, but they will appear if you use query in cube browser or as dataset in SSRS/other tool
You can pass last date in your set by using Tail(Existing [Calendar].[Report Days].[All Members].&[All].&[WantInReport].members, 1).item(0)
Or you can use Format(Now()), which gives you string representation of current system date. However, it depends on locale, so you probably need to remove dots/slashes. See here

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.