Created table in DAX, but can't extract the correct value - dax

I'm attempting to create a measure to give me the rank of a Salesman by Sales. I'll use the measure in a table where one of the columns is Salesman, so there should be the appropriate row context applied. But using
RETURN Calculate( MAXX (RankTable, [Rank] ) )
just gives me a value of 1 for every broker. I can't figure out what to used to just pull out the value for Rank calculated in RankTable. How do I do that?
SumSales = sumx( SalesData, [Sale])
----------
SalesRank =
VAR SummaryTable =
ADDCOLUMNS(
SUMMARIZE( SalesData, [Salesman] ),
"Sales", [SumSales]
)
VAR RankTable =
ADDCOLUMNS(
SummaryTable,
"Rank", RANKX( SummaryTable, [Sales])
)
RETURN
Calculate( MAXX (RankTable, [Rank] ) )
I know that RankTable is correct, since DAX Studio give me this result:
Salesman Sales Rank
A 907 1
B 600 3
C 900 2
D 500 4
Here's code for measure mentioned in comments:
Priced. =
COUNTROWS(
FILTER( 'Cases',
[Date Initiated] >= [MinDate]
&& [Date Initiated] <= [MaxDate]
&& not ISBLANK( [Date To Pricing] )
)
)

I think you might be overcomplicating things, this should work:
SalesRank = RANKX(ALL('Salesdata'[Salesman]), [SumSales])
Reason you're getting 1 for every line is because in a visual the measure is calculated in the context containing a single salesman. So you need to remove this filter using the ALL() function.

Related

Power Bi: how to parameterize Top N visual level filter [duplicate]

This question already has answers here:
Power Bi: Top N visual level filter as Measure
(2 answers)
Closed 6 months ago.
Since PowerBI don't support Top N filter on page level,
I want to use N as a parameter to change it at once per multiple visuals.
Is it possible?
P.S.In this video (9:15) solution for more complex case is provided.
In the end of this article sample file available
Using the sample dataset, insert a new parameter.
Add a measure as follows:
Measure =
IF(
SELECTEDVALUE('Product'[Product Name]) IN
SELECTCOLUMNS(
TOPN(
[Parameter Value],
ADDCOLUMNS( ALLSELECTED( 'Product'),"#Sales", [Sales Amount] ),
[#Sales]
),
"x",
'Product'[Product Name]),
1)
Every visual you want affected by the TopN should have this filter.
That's it.
From usability perspective it's preferable to return Sales Rank in measure.
Solution below is a copy/paste from SQLBI experts solution with minimal code changes ( ALLSELECTED ( 'Product'[Product Name] ) replaced by ALLSELECTED ( 'Product' ) ):
rnkSales =
IF (
ISINSCOPE ( 'Product'[Product Name] ),
VAR ProductsToRank = [TopN Value]
VAR SalesAmount = [Sales Amount]
RETURN
IF (
SalesAmount > 0,
VAR VisibleProducts =
FILTER( -- filters out data with no sales
CALCULATETABLE (
VALUES ( 'Product' ),
ALLSELECTED ( 'Product') -- Use this if VisualFilterTopN equivalent required
//ALLSELECTED ( 'Product'[Product Name] ) -- Original code - returns TopN per dimension
),
NOT ISBLANK( [Sales Amount] ) -- looks more universal then [Sales Amount]>0 (if calculation for Margin required, it could be negative)
)
VAR Ranking =
RANKX (
VisibleProducts,
[Sales Amount],
SalesAmount
)
RETURN
IF (
Ranking > 0 && Ranking <= ProductsToRank,
Ranking
)
)
)

Creating calculated table with MAX and MIN dates in DAX Power BI

I have the following table, imported in Power BI - QOL_Exp (see screenshot example below)
I need to create a calculated table which will filter out values, where Rating = 999 and,
at the same time, will pick only the highest and the lowest Date values from Date column, based on ClientID (see highlighted grey and peach colored areas).
I highlighted in red font - the values that I expect to see in my calculated table
For example, for ClientID = 3052 I will need the records where Date = 11/20/2020 (lowest date for this ClientID) and Date = 5/17/2021 (highest date for this ClientID)
For ClientID = 2666 I will not need the record where Rating = 999 (one of the conditions)
I managed to filter out (to exclude Rating = 999) but struggling with including only Max and MIN date in the new calculated table
This is my DAX:
QOL = CALCULATETABLE(QOL_Exp, QOL_Exp[Rating]<>999)
How should I modify it in order to only leave Max(Date) and Min(Date) records, based on ClientID?
UPD:
Based on the answer given, slightly updated (see below):
QOL =
FILTER (QOL_Exp, QOL_Exp[Rating] <> 999
&&
(( QOL_Exp[Date] = CALCULATE (MIN ( QOL_Exp[Date] ),
ALLEXCEPT(QOL_Exp,QOL_Exp[ClientID])))
|| QOL_Exp[Date] = CALCULATE (MAX ( QOL_Exp[Date] ),
ALLEXCEPT(QOL_Exp, QOL_Exp[ClientID]))))
QOL =
FILTER (
QOL_Exp,
QOL_Exp[Rating] <> 999
&& (
QOL_Exp[Date]
= CALCULATE (
MIN ( QOL_Exp[Date] ),
FILTER (
QOL_Exp,
QOL_Exp[Rating] <> 999
&& QOL_Exp[ClientID] = EARLIER ( QOL_Exp[ClientID] )
)
)
|| QOL_Exp[Date]
= CALCULATE (
MAX ( QOL_Exp[Date] ),
FILTER (
QOL_Exp,
QOL_Exp[Rating] <> 999
&& QOL_Exp[ClientID] = EARLIER ( QOL_Exp[ClientID] )
)
)
)
)

DAX calculation with date range is performing bad

I have a DAX formula that is performing really bad and hopefully someone here can suggest a solution.
I have a table that contains about 400000 rows of data. ProductID's (example field), startdate, enddate and an IsActive flag field. The data out of this table should be reported in several ways. In some reports I want to see all of the active products within a selected period of time and in other reports, I only want to see the number of products that were active on the last day of the month.
So, I have created two DAX queries to calculate this.
First I calculate the active products:
_Calc_Count Fields :=
CALCULATE (
DISTINCTCOUNT ( MyFactTable[ProductID] ),
FILTER (
MyFactTable,
MyFactTable[StartDate] <= CALCULATE ( MAX ( 'Date'[Date] ) )
&& MyFactTable[EndDate] >= CALCULATE ( MIN ( 'Date'[Date] ) )
),
MyFactTable[IsActive] = 1
)
Please be aware of the fact that the report this calculation is used in can also contain a date range (even a whole year (or multiple years) can be selected with a startdate and enddate selected in the filter). The report also slices on other filters like Client Group.
Then I have a second calculation that uses the first one and applies the LASTNONBLANK function:
Last Non Blank Value :=
CALCULATE (
[_Calc_Count Fields],
LASTNONBLANK ( 'Date'[Date], [_Calc_Count Fields] )
)
Both calculations are very, very slow.
Can anyone suggest a better approach? Can the DAX formula be optimized or should it completely be rewritten?
ps. I am using Analysis Services Tabular Model.
Thank you all in advance for your responses!
there are many points to consider for optimizing.
First of all, you need to understand where is the bottleneck.
I would do three separate preliminary tests:
A) change the DISTINCTCOUNT with a simple COUNT
B) Remove the FILTER
C) Remove the IsActive
Then you can understand where to prioritize your effort, however there are some very simple general optimization you can do anyway:
1.Make use of variables, therefore the formula becomes:
_Calc_Count Fields 3:=
VAR _startdate = CALCULATE ( MAX ( 'Date'[Date] ) )
VAR _enddate = CALCULATE ( MIN ( 'Date'[Date] ) )
RETURN
CALCULATE (
DISTINCTCOUNT ( MyFactTable[ProductID] ),
FILTER (
MyFactTable,
MyFactTable[StartDate] <= _startdate
&& MyFactTable[EndDate] >= _enddate
),
MyFactTable[IsActive] = 1
)
2.If you use as first parameter of FILTER an entire Fact Table, Storage Engine will load in memory the Expanded Table which is very expensive. Therefore, as a second step the formula should become:
_Calc_Count Fields 2:=
VAR _startdate = CALCULATE ( MAX ( 'Date'[Date] ) )
VAR _enddate = CALCULATE ( MIN ( 'Date'[Date] ) )
RETURN
CALCULATE (
DISTINCTCOUNT ( MyFactTable[ProductID] ),
MyFactTable[StartDate] <= _startdate && MyFactTable[EndDate] >= _enddate,
MyFactTable[IsActive] = 1
)
Next, based on the preliminary test you can decide where to invest your effort.
The issue is the DISTINCTCOUNT:
- explore some alternative algorithms for approximating DISTINCTCOUNT (HIGH EFFORT)
- try to sort in the data source (back-end) the table by ProductId to allow better compression in AAS
- make sure ProductId is a Integer Data type with Encoding Hint: Value
The issue is in the FILTER:
- Try to change the "&&" with "," (LOW EFFORT)
- Investigate the cardinality of StartDate and EndDate. If they are DateTime, remove the Time part. (LOW EFFORT)
- Try to change the datasource in the back-end and sort by useful fields (for example, StartDate asc, so when AAS will read the table might perform better compression (LOW EFFORT)
- Make sure StartDate and Date are Whole Number data types, with Encoding Hint: Value (LOW EFFORT)

How to write an optimized DAX Measure to aggregate a value by two group by attributes

What if we need to aggregate (Sum) of a value group by two attributes in DAX. I wrote the following measure with Summarize function but it is very slow.
Reorder :=
SUMX (
SUMMARIZE (
TableA,
TableA[ProdID],
TableA[CustID],
"ReordersCount",
VAR VarInvoiceCount =
SUM ( TableA[InvoiceCount] )
RETURN
IF ( VarInvoiceCount > 0, VarInvoiceCount - 1, 0 )
),
[ReordersCount]
)
I also looked for SummarizeColumns but its not working in the report when I am applying other attributes slicers. May be I am missing something?
Looking for optimized solution. Many thanks in advance.
Consider the following approach:
First, create a measure for total number of invoices:
Total Invoice Count = SUM(TableA[InvoiceCount])
Second, create a measure to count a number of first-time invoices, which is simply a number of unique product-customer combinations in your table:
First Invoice Count =
COUNTROWS ( SUMMARIZE ( TableA, TableA[CustID], TableA[ProdID] ) )
Finally, the desired result is simply the difference of these two measures:
Reorder Count = [Total Invoice Count] - [First Invoice Count]
The formula will respond properly to all slicers and filters, and should be very fast because there are no nested iteration loops such as SUMX(SUMMARIZE()), no context transitions and no call-backs inside the loops caused by using IF statements (that's a bit of an advanced topic).
Of course, you can put everything in one measure using variables:
Reorder Count =
VAR Total_Invoice_Count = SUM(TableA[InvoiceCount])
VAR First_Invoice_Count = COUNTROWS ( SUMMARIZE ( TableA, TableA[CustID], TableA[ProdID] ) )
VAR Reorder_Count = Total_Invoice_Count - First_Invoice_Count
RETURN Reorder_Count
although personally I prefer to break measures down because individual measures are easier to understand and debug, and they might have their own use.
The above approach is very efficient, but it assumes that TableA contains only valid orders. If it also has cancellations, returns, etc., that might have zero or negative Invoice counts, then you will have to use a less efficient approach, such as:
Reorder Count =
SUMX (
SUMMARIZE ( TableA, TableA[CustID], TableA[ProdID] ),
VAR Reorder_Count = CALCULATE ( SUM ( TableA[Invoice] ) ) - 1
RETURN
IF ( Reorder_Count > 0, Reorder_Count, 0 )
)
or:
Reorder Count =
SUMX (
SUMMARIZE ( TableA, TableA[CustID], TableA[ProdID] ),
MAX(CALCULATE ( SUM ( TableA[Invoice] ) ) - 1, 0) )
Nevertheless, they should be still faster than your original formula.

Calculating payback period using DAX

I'm working on some calculations for capital budgeting, and I have the following two tables in my data model
I'm trying to build out a calculated column in DAX to determine the payback period for each project in the Project table. I've put together the calculation here, I'm just not sure exactly how to execute this in DAX.
Logical Steps for Calculating Payback Period:
For each Project, find the cumulative sum for each date for relevant metrics (Include OpEx Savings and OpEx Implementation Cost, but not Revenue or Working Capital)
Find the MIN date where cumulative sum is greater than zero (the "break-even" date")
Find the MIN date with non-zero implementation cost ("Investment date")
Find the difference (in months) between #2 and #3 to determine payback period
EDIT:
The answer for the listed project is 7 months. I've built an intermediate table in Excel to develop the answer, but I'd like to be able to do this directly in a PowerPivot table with DAX.
I've produced this as a solution:
Create values, which makes sure cost are - and savings are + (ValCorr)
Create a running sum (RunningSum)
Find Investment Date (InvestmentDate)
Find Breakeven Date (BreakEvenDate)
Find Difference (Payback)
DAX:
RunningSum =
CALCULATE(SUM(Impacts[ValCorr]);
FILTER(
ALL(Impacts);
Impacts[ProjectID] = EARLIER(Impacts[ProjectID]) &&
Impacts[Date] <= EARLIER(Impacts[Date])
))
InvestmentDate =
CALCULATE (
FIRSTNONBLANK ( Impacts[Date]; 0 );
FILTER ( ALL ( Impacts ); Impacts[RunningSum] <> 0 )
)
BreakEvenDate =
CALCULATE (
FIRSTNONBLANK ( Impacts[Date]; 0 );
FILTER ( ALL ( Impacts ); Impacts[RunningSum] > 0 )
)
Payback = DATEDIFF(Impacts[InvestmentDate];Impacts[BreakEvenDate];MONTH)
Result:
Good luck!
After a fair amount of trial and error, I came up with a solution.
Step 1: Build out a helper metrics table. This serves 2 purposes: (a) excludes irrelevant metrics (like revenue), and (b) ensure costs are negative and savings are positive.
Metrics Table
Step 2: Build 2 helper measures that will go into the virtual, summarized, intermediate table.
CumulativeTotalMetric :=
CALCULATE (
SUMX (
Impact,
Impact[Latest Estimate Monthly Values]
* RELATED ( BaseMetrics[Payback Period Multiplier] )
),
FILTER ( ALL ( Impact[Month] ), Impact[Month] <= MAX ( Impact[Month] ) )
)
TotalMetric :=
SUMX (
Impact,
Impact[Latest Estimate Monthly Values]
* RELATED ( BaseMetrics[Payback Period Multiplier] )
)
Step 3: Create the final measure that creates the virtual table (BaseTable), and performs logical operations on it to arrive at the final payback period.
Payback Period (Years) :=
VAR BaseTable =
ADDCOLUMNS (
SUMMARIZE ( Impact, Impact[initiative #], Impact[snapshot], Impact[Month] ),
"Cumulative Total Impact", CALCULATE ( [CumulativeTotalMetric] ),
"Total Impact", CALCULATE ( [TotalMetric] )
)
VAR LastCumulativeLossDate =
MAXX ( FILTER ( BaseTable, [Cumulative Total Impact] < 0 ), [Month] )
VAR BreakEvenDate =
MINX (
FILTER (
BaseTable,
[Month] > LastCumulativeLossDate
&& [Cumulative Total Impact] > 0
),
[Month]
)
VAR InitialInvestmentDate =
MINX ( FILTER ( BaseTable, [Total Impact] < 0 ), [Month] )
RETURN
IF (
OR ( ISBLANK ( InitialInvestmentDate ), ISBLANK ( BreakEvenDate ) ),
BLANK (),
( BreakEvenDate - InitialInvestmentDate )
/ 365
)
This last meaure is pretty complicated. It uses progressive, dependent variables. It starts with the same base table, and defines variables that are used in subsequent variables. I'm no DAX expert, but I suspect using these variables helps with the calculation efficiency.
EDIT: I should note that I didn't use this measure as a calculated column -- I simply used it in a pivot table which is the same "shape" as the "Projects" table above -- one line per project / initiative.

Resources