MDX Replace Range With Filter - filter

While looking at the following answer I wanted to replace the range with a filter.
MDX - Concurrent calculations based on a "record time range"?
The MDX is:
with member [Measures].[TotalUsed] as sum({[Date].[YQM].&[20090501]:[Date].[YQM].&[20090907]}, [Measures].[Used])
select {[Measures].[Total Used]}on columns,
{[Color].[Colors].[All].MEMBERS}on rows
from [Cube]
I'm trying to replace the Date range with a filter like this:
with member [Measures].[TotalUsed] as sum(FILTER([Date].[YQM], [Date].[YQM] < [Date].[YQM].&[20090907]), [Measures].[Used])
select {[Measures].[Total Used]}oncolumns,
{[Color].[Colors].[All].MEMBERS}on rows
from [Cube]
What is the conditional statement looking for in terms of comparing values? Any Help would be great!
Thanks!

The Filter statement needs a SET and then an EXPRESSION to filter on. You can drop this right inside your SUM function. The expression part of the filter can be almost anything, but it has to evaulate to true/false for each cell in the SET.
-- FILTER ( SET, EXPRESSION)
It's a bit tough not knowing what your data is structured like but your statment would probably end up like the following, filtering rows with less than 50 'UnUsed' for your timeperiods, and then summing them as an example.
`
WITH MEMBER [Measures].[TotalUsed]
AS SUM (FILTER ( [Date].[YQM].members, [Measures].[UnUsed] > 50 ),
[Measures].[Used] )
SELECT {[Measures].[Total Used]} ON COLUMNS,
{[Color].[Colors].[All].MEMBERS} ON ROWS
FROM [Cube]

Related

Sum of only Distinct values in a Column in DAX

I have table[Table 1] having three columns
OrganizationName, FieldName, Acres having data as follows
organizationname fieldname Acres
ABC |F1 |0.96
ABC |F1 |0.96
ABC |F1 |0.64
I want to calculate the sum of Distinct values of Acres
(eg: 0.96+0.64) in DAX.
One of the problems with doing what you want is that many measures rely on filters and not actual table expressions. So, getting a distinct list of values and then filtering the table by those values, just gives you the whole table back.
The iterator functions are handy and operate on table expressions, so try SUMX
TotalDistinctAcreage = SUMX(DISTINCT(Table1[Acres]),[Acres])
This will generate a table that is one column containing only the distinct values for Acres, and then add them up. Note that this is only looking at the Acres column, so if different fields and organizations had the same acreage -- then that acreage would still only be counted once in this sum.
If instead you want to add up the acreage simply on distinct rows, then just make a small change:
TotalAcreageOnDistinctRows = SUMX(DISTINCT(Table1),[Acres])
Hope it helps.
Ok, you added these requirements:
Thank You. :) However, I want to add Distinct values of Acres for a
Particular Fieldname. Is this possible? – Pooja 3 hours ago
The easiest way really is just to go ahead and slice or filter the original measure that I gave you. But if you have to apply the filter context in DAX, you can do it like this:
Measure =
SUMX(
FILTER(
SUMMARIZE( Table1, [FieldName], [Value] )
, [FieldName] = "<put the name of your specific field here"
)
, [Value]
)

How to filter by measure values in MDX while having dimension members in both axis

I'm developing an application that uses a tabular database to show some business data.
I need to provide some basic filtering over measures values (equal to, greater than, lesser than etc.) and I'm currently analyzing the proper way to generate the MDX.
Looking at some documentation (and other threads on this site), I found that the most efficient approach would be using the FILTER or HAVING functions to filter out undesired values.
Unfortunately all examples normally include measures on one axis and dimension member on the other, but I potentially have dimension members in both axis and can't find a proper solution to use such functions to filter by measure value.
What have I done so far?
To make it easier to explain, let's say that we want to get the yearly sales quantities by product class filtering quantity > 1.3 milions
Trying to use HAVING or FILTER Functions, the resulting MDX I came up with is
SELECT
NON EMPTY {[YearList].[Year].[Year].MEMBERS * [Measures].[Qty]}
HAVING [Measures].[Qty] > 1.3e6 ON COLUMNS,
NON EMPTY {[Classes].[cClass].[cClass].MEMBERS}
HAVING [Measures].[Qty] > 1.3e6 ON ROWS
FROM [Model]
or
SELECT
NON EMPTY FILTER({[YearList].[Year].[Year].MEMBERS * [Measures].[Qty]},
[Measures].[Qty] > 1.3e6) ON COLUMNS,
NON EMPTY FILTER({[Classes].[cClass].[cClass].MEMBERS} ,
[Measures].[Qty] > 1.3e6) ON ROWS
FROM [Model]
But this is of course leading to unexpected result for the final user because the filter is happening on the aggregation of the quantities by the dimension on that axis only, which is greater then 1.3M
The only way I found so far to achieve what I need is to define a custom member with an IIF statement
WITH
MEMBER [Measures].[FilteredQty] AS
IIF ( [Measures].[Qty] > 1.3e6, [Measures].[Qty], NULL)
SELECT
NON EMPTY {[YearList].[Year].[Year].MEMBERS * [Measures].[FilteredQty]} ON COLUMNS,
NON EMPTY {[Classes].[cClass].[cClass].MEMBERS} ON ROWS
FROM [Model]
The result is the one expected:
Is this the best approach or I should keep using FILTER and HAVING functions? Is there even a better approach I'm still missing?
Thanks
This is the best approach. You need to consider how MDX resolves result. In the example above it is a coincidence that your valid data in a continous region of first four columns of first row. Lets relax the filtering clause and make it >365000. Now take a look at last row of the result, the first two columns and the last column are eligible cells but the third and fourth column is not eligible. However your query will report it as null and the non empty function will not help. The reason is that non empty needs the entire row to be null
Now the question that why filter is not eliminating the cell? Filter will eliminate a row or column when the criteria is greater then the sum on the other axis. So if filter is on columns the filter value has to be greater than the sum of rows for that column. Take a look at the sample below as soon as you remove the comments the last column will be removed.
select
non empty
filter(
([Measures].[Internet Sales Amount]
,{[Date].[Calendar Year].&[2013],[Date].[Calendar Year].&[2014]}
,[Date].[Calendar Quarter of Year].[Calendar Quarter of Year]
),([Date].[Calendar Year].currentmember,[Date].[Calendar Quarter of Year].currentmember,[Product].[Subcategory].currentmember,[Measures].[Internet Sales Amount])>45694.70--+0.05
)
on columns
,
non empty
[Product].[Subcategory].members
on rows
from
[Adventure Works]
Edit another sample added.
with
member [Measures].[Internet Sales AmountTest]
as
iif(([Date].[Calendar Year].currentmember,[Date].[Calendar Quarter of Year].currentmember,[Product].[Subcategory].currentmember,[Measures].[Internet Sales Amount])>9000,
([Date].[Calendar Year].currentmember,[Date].[Calendar Quarter of Year].currentmember,[Product].[Subcategory].currentmember,[Measures].[Internet Sales Amount]),
null
)
select
non empty
({[Measures].[Internet Sales Amount],[Measures].[Internet Sales AmountTest]}
,{[Date].[Calendar Year].&[2013]}
,[Date].[Calendar Quarter of Year].[Calendar Quarter of Year]
)
on columns
,
non empty
[Product].[Subcategory].[Subcategory]
on rows
from
[Adventure Works]

DAX - Meassure that sums only the first occurance by group

I'm trying to figure out how to build a measure that sums a total, but only taking the first non-empty row for a user.
For example, my data looks like the below:
date user value
-----------------
1/1/17 a 15
2/1/17 a 12
1/1/17 b null
5/1/17 b 3
I'd therefore like a result of 18 (15 + 3).
I'm thinking that using FIRSTNONBLANK would help, but it only takes a single column, I'm not sure how to give it the grouping - perhaps some sort of windowing is required.
I've tried the below, but am struggling to work out what the correct syntax is
groupby(
GROUPBY (
myTable,
myTable[user],
“Total”, SUMX(CURRENTGrOUP(), FIRSTNONBLANK( [value],1 ))
),
sum([total])
)
I didn't have much luck getting FIRSTNONBLANK or GROUPBY to work exactly how I wanted, but I think I found something that works:
SUMX(
ADDCOLUMNS(
ADDCOLUMNS(VALUES(myTable[User]),
"FirstDate",
CALCULATE(MIN(myTable[Date]),
NOT(ISBLANK(myTable[Value])))),
"FirstValue",
CALCULATE(SUM(myTable[Value]),
FILTER(myTable, myTable[Date] = [FirstDate]))),
[FirstValue])
The inner ADDCOLUMNS calculates the first non-blank date values for each user in the filter context.
The next ADDCOLUMNS, takes that table of users and first dates and for each user sums each [value] that occurred on each respective date.
The outer SUMX takes that resulting table and totals all of the values of [FirstValue].

Avoid duplicate values for certain column in DAX query

I am using the following statement to get a result table:
EVALUATE
(
CALCULATETABLE
(
ADDCOLUMNS (
'Case',
"Casenumber", RELATED( 'CaseDetails'[nr]),
),
'Case'[Date] <= value(#dateto) )
)
However, I want to only get one record pr casenumber. In SQL I would solve this with a GROUP BY statement, but how should I do this in DAX? Case also has a dimkey, so several cases with the same casenumber can have different dimkeys.
Try this:
EVALUATE
CALCULATETABLE(
SUMMARIZE(
Case
,<comma-separated list of fields from Case you want>
,"CaseNumber"
,RELATED(CaseDetails[nr])
)
,Case[Date] <= VALUE(#dateto)
)
SUMMARIZE() takes a table as its first argument, then a comma-separated list of fields from that table and any tables that it is related to where it is on the many side (thus in a star schema, SUMMARIZE()ing the fact table will allow you to refer directly to any dimension table field), followed by a comma-separated list of , pairs where is a quoted field name and is a scalar value which is evaluated in the row context of the table in the first argument.
If you don't need to rename CaseDetails[nr], then the query would look like this (just for an illustrative example):
EVALUATE
CALCULATETABLE(
SUMMARIZE(
Case
,<comma-separated list of fields from Case you want>
,CaseDetails[nr]
)
,Case[Date] <= VALUE(#dateto)
)
In such a query, all fields will come through with column headings in the format of 'table'[field], so there is no ambiguity if you have identical field names in multiple related tables.
Edit to address new information in original:
SUMMARIZE(), just like SQL's GROUP BY clause will not eliminate distinct values from the resultset. If there is a field that is a higher cardinality than the field you want to group by, you will always see duplicates.
Is your [DimKey] necessary in the resultset? If yes, then there's no way to decrease the size of your resultset smaller than the number of distinct values of [DimKey].
If [DimKey] is unnecessary, simply omit it from the list of fields in SUMMARIZE().
If you want only a specific [DimKey], e.g. the most recent (assuming it's an IDENTITY field and the max value is the latest), then you can bring it in with another ADDCOLUMNS() wrapped around your current SUMMARIZE():
EVALUATE
ADDCOLUMNS(
SUMMARIZE(
Case
,<comma-separated list of fields from Case except for [DimKey]>
,"CaseNumber"
,RELATED(CaseDetails[nr])
)
,"MaxDimKey"
,CALCULATE(MAX(Case[DimKey]))
)

Oracle Error : Maximum number of expressions in a list is 1000

I am working in C#.Net and Oracle. i am passing a string to a query. i had used this code for concating all the item id's
List<string> listRetID = new List<string>();
foreach (DataRow row in dtNew.Rows)
{
listRetID.Add(row[3].ToString());
}
This concatination goes above 10,000. so i am getting the error message like this..
ORA-01795: maximum number of expressions in a list is 1000
How to fix this..
The documentation states:
A comma-delimited list of expressions can contain no more than 1000
expressions. A comma-delimited list of sets of expressions can contain
any number of sets, but each set can contain no more than 1000
expressions.
Presumably you're using this string as the contents of in IN (...) restriction, in which case there isn't really anything you can do - this just won't work. A common way to work around this is to generate a dummy table as a subquery or common table expression (CTE) and joining to that, but I'm not sure how you'd translate your List - possibly similar to whatever you're doing with your IN clause. You'd want to end up with your query looking something like:
with tmp_tab as (
select <val1 from list> as val from dual
union all select <val2 from list from dual
union all select <val3 from list from dual
...
)
select <something>
from <your table> yt
join tmp_tab tt on yt.<field> = tt.val
But that requires generating the entire (huge) query including the CTE each time you run it, and there's no opportunity to use bind variables.
You might find something like this approach more palatable.
You can have 10 lists of 1000 items instead of 1 list of 10000 items.
WHERE some_column IN (1,2,...,1000)
OR some_column IN (1001,1002,...2000) -- etc.
Not a C# guy but I would just split the list listRetID in multiple lists or create a list of lists
Then loop through that list of lists and perform the query on each element of the list.
What is the intent of your query?
It looks like you are selecting rows that have some column equal to the 3rd column of one of the records of some query.
The correct way of doing this is either an SQL join or a subquery. There is absolutely no need to bring this into C# code. For example, using a subquery you can write something like this:
SELECT *
FROM atable
WHERE afield IN (
SELECT field3
FROM someothertable)

Resources