MDX Query - return a member contained in the filter - sql

I have an MDX query that is filtering on a particular member, but I need it to return the actual member value as well.
For example:
SELECT NON EMPTY { [Measures].[__No measures defined] } ON COLUMNS, NON EMPTY { ([Archive].[SiteId].[SteId] }ON ROWS FROM [Model] WHERE ( {[Archive].[SiteId].&[{e7672ff4-7f0c-4806-8453-744a17bde4ca}],[Archive].[SiteId].&[{bb7d8f41-c88a-4bcb-ade8-d0533190185a}],[Archive].[SiteId].&[{04cd27b6-e239-4d27-bc58-27f0a8733193}]} )
so in SQL it would basically be -
Select SiteId from Model where SiteId In .....
However this won't work because it says the SiteId Member is already contained in the filter and so appear twice in the query!
So how can filter on SiteId AND return the SiteId?
Thanks!

I decided to use DAX instead. In fact DAX enabled me to perform some better manipulation given my data that sped up the overall application.

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]

icCube MDX on distinct count in relation to same dimension in axis or filter

I have the following MDX statement on the $Monitoring cube:
WITH
MEMBER [Measures].[Unique Users] AS distinctcount(([User].[User].[User L].members
, [Measures].[Open Report Count])),format_string="#,#0"
SELECT
NON EMPTY { {[Measures].[Unique Users],[Measures].[Open Report Count]} } ON COLUMNS,
NON EMPTY { [Time].[Time].[Day L] } ON ROWS
FROM ( SELECT
{ lag(strtomember("[Time].[Time].["+right("0"+str(day(SchemaRefreshTime())),2) +"-"+ right("0"+str(month(SchemaRefreshTime())),2) + "-"+str(year(SchemaRefreshTime()))+ "]"), 6):strtomember("[Time].[Time].["+right("0"+str(day(SchemaRefreshTime())),2) +"-"+ right("0"+str(month(SchemaRefreshTime())),2) + "-"+str(year(SchemaRefreshTime()))+ "]") } ON 0 FROM [$Monitoring])
/*ic3navigation*/
axis 1 NON EMPTY order(nonempty(Descendants([Report].[Report], ,leaves),[Open Report Count]),[Open Report Count],desc)
FILTERBY /*ic3*/ {[Time].[Time].[ALL].&[2015].&[2015-11-27].&[27-11-2015]}
FILTERBY /*ic3*/ {[User].[User].[All Users].&[<user>]}
*) change <user> with the actual user name
*) the ...lag.. formula is used to give the last 7 days based on schema refresh time
***) this MDX query can be run on any $Monitoring cube if you have filled in an existing user
I would expect the distinctcount function to take into account the FILTERBY. So the result should be 1 (there is just one user selected). The strange thing is, that it does not. It shows more than one user, so I assume the FILTERBY on users is not taken into account for the distinctcount.
The same thing happens when I move the FILTER BY to the AXIS or to the ROWS or COLUMNS.
Is this a bug or is this something how MDX/ MDX++ works in icCube?
Please advise.
It's the expected behaviour. Welcome to advanced MDX !
A FilterBy is exactly the same as a sub-select.
Members are not filtered by a subselect or a where clause in a calculated members.
In a calculated member, a tuple that defines a hierarchy will 'overwrite' the one defined in a subquery or where clause.
------ UPDATE ------
If you want to filter the set with the where clause/subselect you've the EXISTING operator.
MEMBER [Measures].[Unique Users] AS count( Existing [User].[User].[User L].members),format_string="#,#0"
if you want only users with data for the cell tuple :
MEMBER [Measures].[Unique Users] AS count( nonempty( Existing [User].[User].[User L].members, [Measures].[Open Report Count])),format_string="#,#0"
If you've a large number of users I'd advise adding a measure [Distinct Users] that is a distinct count on the user id. This way you avoid all complexity that we're facing here.

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

Easiest way to programmatically generate MDX rowcount query?

Right now I'm dealing with a program that can generate and return SQL or MDX queries (depending on the source database of the queries). I'm working on adding a feature that counts all the rows returned by a given query.
Now, I have some small background with SQL, so I was able to parse table names and generate a rowcount. However, MDX is a completely new beast for me.
In SQL, I'm creating:
SELECT
COUNT(SUM)
AS ROWS
FROM
(
COUNT(*) AS COUNT FROM TABLE1
UNION ALL
COUNT(*) AS COUNT FROM TABLE2
UNION ALL
COUNT(*) AS COUNT FROM TABLE3
ETC...
)
Now, what I'm wondering is, how would I do something similar with MDX? I've done some reading on MDX, and from what I gathered the basic notation is
[Dimension].[Hierarchy].[Level]
Now with SQL, I parsed the table names out of a larger generated query and simply inserted them into a new programmatically generated query. What would I have to grab from a larger MDX query to generate my own rowcounting query and sending it off to run? A simpler example of the MDX I'm dealing with would be:
WITH
MEMBER [BUSINESS1].[XQE_RS_CM1] AS '([BUSINESS1].[COMPANY_H].[all])', SOLVE_ORDER = 8
MEMBER [BUSINESS2].[XQE_RS_CM0] AS '([BUSINESS2].[all])', SOLVE_ORDER = 4
SELECT
NON EMPTY {[BUSINESS2].[ALL_TIME_H].[CALENDAR_YEAR_L].MEMBERS AS [XQE_SA1] , HEAD({[BUSINESS2].[XQE_RS_CM0]}, COUNT(HEAD([XQE_SA1]), INCLUDEEMPTY))} DIMENSION PROPERTIES PARENT_LEVEL, PARENT_UNIQUE_NAME ON AXIS(0),
NON EMPTY {[BUSINESS1].[COMPANY_H].[COMPANY_CD__L].MEMBERS AS [XQE_SA0] , HEAD({[BUSINESS1].[XQE_RS_CM1]}, COUNT(HEAD([XQE_SA0]), INCLUDEEMPTY))} DIMENSION PROPERTIES PARENT_LEVEL, PARENT_UNIQUE_NAME ON AXIS(1),
NON EMPTY {[Measures].[Measures].[BUSINESS3]} DIMENSION PROPERTIES PARENT_LEVEL, PARENT_UNIQUE_NAME ON AXIS(2)
FROM
[SOURCE] CELL PROPERTIES CELL_ORDINAL, FORMAT_STRING, VALUE
Any insight would be awesome, thanks.
At first glance your script looks reasonable then after unravelling it becomes a bit(!) more complex.
The main difference between this and other scripts is its use of axis(2). In a sub-select extra dimensions are often used but this is a little odd as most clients can't handle 3 dimensional cellsets - so I'm intrigued by what is consuming this info?
Also the member [BUSINESS1].[XQE_RS_CM1] is a single member as is [BUSINESS2].[XQE_RS_CM0] so what is the point of the sections HEAD... ?
WITH
MEMBER [BUSINESS1].[XQE_RS_CM1] AS
([BUSINESS1].[COMPANY_H].[all]), SOLVE_ORDER = 8
MEMBER [BUSINESS2].[XQE_RS_CM0] AS
([BUSINESS2].[all]), SOLVE_ORDER = 4
SELECT
NON EMPTY
{[BUSINESS2].[ALL_TIME_H].[CALENDAR_YEAR_L].MEMBERS AS [XQE_SA1]
,HEAD(
{[BUSINESS2].[XQE_RS_CM0]},
COUNT(
HEAD([XQE_SA1])
,INCLUDEEMPTY
)
)}
ON AXIS(0),
NON EMPTY
{[BUSINESS1].[COMPANY_H].[COMPANY_CD__L].MEMBERS AS [XQE_SA0]
,HEAD(
{[BUSINESS1].[XQE_RS_CM1]},
COUNT(
HEAD([XQE_SA0])
,INCLUDEEMPTY
)
)}
ON AXIS(1),
NON EMPTY
{
[Measures].[Measures].[BUSINESS3]
}
ON AXIS(2)
FROM
[SOURCE]
Does the following return the same data as the original script?
SELECT
NON EMPTY
{
[BUSINESS2].[ALL_TIME_H].[CALENDAR_YEAR_L].MEMBERS
,[BUSINESS2].[all]
}
ON 0,
NON EMPTY
{
[BUSINESS1].[COMPANY_H].[COMPANY_CD__L].MEMBERS
,[BUSINESS1].[COMPANY_H].[all]
}
ON 1
FROM [SOURCE]
WHERE [Measures].[Measures].[BUSINESS3];
All you need to calculate then is the count of members returned in the following set on the rows:
{
[BUSINESS1].[COMPANY_H].[COMPANY_CD__L].MEMBERS
,[BUSINESS1].[COMPANY_H].[all]
}

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.