Thanks in advance for helping this struggling newbie.
Can this aggregation be done with a single DAX statement?
I need to get to the "50" result using a measure if possible...
excel data screen capture
Here is a DAX measure performing this calculation (replace YourTable with the actual table name):
=
SUMX (
VALUES ( YourTable[Item] ),
MAXX (
VALUES ( YourTable[Round] ),
CALCULATE( SUM ( YourTable[Value] ) )
)
)
This measure uses nested iterators SUMX and MAXX to iterate over the Item and Round dimensions.
Related
The following DAX formula works on Power BI but not on Power Pivot (don't show error but blank cells) using the same exact data model (checked this many times).
It's used in a calculated column.
Actual Units SO =
CALCULATE (
SUM ( COM_SellOut[QuantitySold] ),
FILTER ( COM_SellOut, COM_SellOut[Date] >= TMK_Promotion[FromDate] ),
FILTER ( COM_SellOut, COM_SellOut[Date] <= TMK_Promotion[ToDate] ),
FILTER ( COM_SellOut, COM_SellOut[ProductCode] = TMK_Promotion[ProductCode] ),
FILTER ( COM_Customers, COM_Customers[id] = TMK_Promotion[Customer] )
)
A little context: this formula iterates a promotion table and calculates the units sold of a given product, in a given customer between a given period. Works flawlessly in PowerBI but not on PowerPivot.
Any ideas of what could be causing the problem?
Thanks in advance!
Power Pivot and Power BI use the same engine, so the same version DAX works in both applications. Are you using a colon (Actual Units SO :=) in front of your equal sign (no space). In Power Pivot it's a must whereas in Power BI it's optional. I see in your example there is no colon, so your DAX measure won't work in Power Pivot. It's a syntax issue not a model or DAX issue.
Actual Units SO :=
CALCULATE (
SUM ( COM_SellOut[QuantitySold] ),
FILTER ( COM_SellOut, COM_SellOut[Date] >= TMK_Promotion[FromDate] ),
FILTER ( COM_SellOut, COM_SellOut[Date] <= TMK_Promotion[ToDate] ),
FILTER ( COM_SellOut, COM_SellOut[ProductCode] = TMK_Promotion[ProductCode] ),
FILTER ( COM_Customers, COM_Customers[id] = TMK_Promotion[Customer] )
)
I think you can get a better performance by using logical and in one filter rather than nesting your filters :
Actual Units SO =
CALCULATE (
SUM ( COM_SellOut[QuantitySold] ),
FILTER ( COM_SellOut, COM_SellOut[Date] >= TMK_Promotion[FromDate]
&& COM_SellOut, COM_SellOut[Date] <= TMK_Promotion[ToDate]
&& COM_SellOut, COM_SellOut[ProductCode] = TMK_Promotion[ProductCode]
&& COM_Customers, COM_Customers[id] = TMK_Promotion[Customer]
)
)
I am wondering what the difference is between these two DAX expressions which each return what I need:
(1) =calculate([PctMkt], FILTER ( ALL ( BondDim), BondDim[Quality] = "HY" ))
(2) =calculate([PctMkt], ALL(BondDim), BondDim[Quality] = "HY" )
Does the DAX engine make these two expressions equivalent? Is (2) just short hand for (1)? Also, would (1) calculate more quickly? Trying to make sure that I don't cause problems in the pivot table by "hacking" together calculated measures. These measures allow the user to drilldown to a lower grain while keeping higher level data in context of the pivot table.
A simpler, similar question is well-known.
CALCULATE (
[PctMkt],
BondDim[Quality] = "HY"
)
is the shortened equivalent of
CALCULATE (
[PctMkt],
FILTER (
ALL ( BondDim[Quality] ),
BondDim[Quality] = "HY"
)
)
Your formulas need a bit more thought.
When ALL is used as an argument of CALCULATE, it only removes filters (like REMOVEFILTERS) rather than acting as a table expression.
When ALL ( < table > ) is used as an argument of FILTER, it is necessarily a table expression.
The first link I gave gives a detailed example of how this distinction can make an important difference. I'll provide another example here:
Suppose MarketDim has a one-to-many relationship with BondDim (and is not bidirectional) on the ID column from each and the tables are as follows:
BondDim MarketDim
Quality ID ID Pct
------------- ----------
HY 1 1 5%
VY 1 2 10%
XY 2 3 20%
Let's suppose [PctMkt] := MAX ( MarketDim[Pct] )
Then, in your first formula (1), the FILTER argument is the following table:
Quality ID
-------------
HY 1
Thus, the result of (1) can only be 5% (or blank) since ID = 1 is the only option.
In your second formula (2), there are no table arguments since ALL ( BondDim ) is only removing filters and BondDim[Quality] = "HY" only acts on a single column. Without table arguments, since MarketDim filters BondDim but not vice versa (since it's a single direction relationship), neither of these column filter arguments has any effect on the measure I've defined (it might on your actual measure though).
Thus, the result of (2) is the same as just CALCULATE ( [PctMkt] ), which will be 20% unless there is filtering on MarketDim to exclude ID = 3.
Note: This simplification for (2) does not hold if [PctMkt] operates on BondDim columns or any table columns that are filtered by BondDim in your model. I.e. the filters propagate "downstream" across relationships but not "upstream".
The second one
CALCULATE (
[PctMkt],
ALL ( BondDim ),
BondDim[Quality] = "HY"
)
is internally expanded by DAX as the equivalent formula
CALCULATE (
[PctMkt],
ALL ( BondDim ),
FILTER (
ALL ( BondDim[Quality] ),
BondDim[Quality] = "HY"
)
)
So it is not the same as the first one
CALCULATE (
[PctMkt],
FILTER (
ALL ( BondDim ),
BondDim[Quality] = "HY"
)
)
The difference is that the first one uses the whole BondDim table as a filter while the second one is using just one column of the same table
I am struggling with a "simple" function that is killing me. I am simply trying to get the subtotal of each group in a pivot table. I d like to compute the percentage of each subgroup as my input data are wrong. It seems I cannot do the classic EARLIER, and there is no this or current or whatever...
CALCULATE (
SUM ( table1[numbers] ),
FILTER (
ALL ( table1 ),
table1[Names] = FIRSTNONBLANK ( ALL ( table1[Names] ), tables[Names] )
)
)
Thanks
Found it! Absolutely counterintuitive to me, but it works...
=CALCULATE (
SUM ( table1[numbers] ),
ALLEXCEPT ( table1, table1[Names])
)
I would like to get the running sum of [Days Past Due] Column grouped by project number and for each project number, get the value for each phase/end date.
IN SQL I would do:
SELECT Project_number
,phase
,Sum(Days Past Due) RunningTotal
FROM Table
GROUP BY Project_number
,phase
ORDER BY Project_number
,phase
I would do something similar in DAX please.
I try that:
CALCULATE (
SUM ( DataSource[Days Past Due] ),
ALLEXCEPT ( DataSource, DataSource[Project Number] )
)
It gives me the total for each project number repeated in the 4 rows. That's not what I want exactly. I need to apply a second filter on that.
Please look at the attachment, it has the last column with the desired output.
Thank you in advance for your suggestions.
You can adjust your attempt like this:
Cumulative Days Past Due =
CALCULATE(
SUM( DataSource[Days Past Due] ),
FILTER(
ALLEXCEPT( DataSource, DataSource[Project Number] ),
DataSource[End Date] <= MAX( DataSource[End Date] )
)
)
Note that you can include more filtering conditions in the FILTER function by joining more conditions with &&. You can add more filter conditions inside CALCULATE as well. Here's an example:
Cumulative Days Past Due =
CALCULATE(
SUM( DataSource[Days Past Due] ),
FILTER(
ALLEXCEPT( DataSource, DataSource[Project Number] ),
DataSource[End Date] <= MAX( DataSource[End Date] )
&& DataSource[Start Date] > DATE( 2018, 12, 31 )
),
DataSource[Phase] = "Scope"
)
The documentation for CALCULATE and FILTER might be useful for further clarification:
https://dax.guide/calculate/
https://learn.microsoft.com/en-us/dax/calculate-function-dax
https://dax.guide/filter/
https://learn.microsoft.com/en-us/dax/filter-function-dax
If you are trying to write this formula in a calculated column, it will not work as expected and you will need to use EARLIER instead of MAX:
Cumulative Days Past Due =
CALCULATE(
SUM( DataSource[Days Past Due] ),
FILTER(
ALLEXCEPT( DataSource, DataSource[Project Number] ),
DataSource[End Date] <= EARLIER( DataSource[End Date] )
)
)
The reason for this is that in a measure MAX is calculated within its local filter context but in a calculated column the context is different and you use EARLIER to refer to the earlier row context, that is, the End Date in the current row of the larger table (rather than the smaller FILTER table).
If you want something that works either as a measure or a calculated column, then #RADO's solution is pretty close and you can write this:
Cumulative Days Past Due =
VAR CurrDate =
CALCULATE( MAX( DataSource[Start Date] ) )
RETURN
CALCULATE(
SUM( DataSource[Days Past Due] ),
ALLEXCEPT( DataSource, DataSource[Project Number] ),
DataSource[End Date] <= CurrDate
)
In this version, the MAX works just as it did before in the first version above and it should also work in a calculated measure because wrapping the MAX in a CALCULATE performs a context transition that transforms the row context into a filter context corresponding to that single row.
You can drop the CALCULATE wrapper for just a measure and drop both the CALCULATE and MAX functions for a simpler calculated column. In either of these cases, this variable version is likely the more performant one since the ALLEXCEPT function is optimized to work efficiently within CALCULATE rather than having to instantiate a new table when using FILTER.
For further details on cumulative totals, I recommend DAX Patterns as a resource:
https://www.daxpatterns.com/cumulative-total/
I am new to DAX and have created two measures to get the total pay per employee then lookup that total pay into a table and return a value in my Power Pivot.
Total Pay Measure:
NMRPaySum:=SUMX(Pay,[Regular Pay]+[Overtime Pay]+[Other Pay])
Range Lookup Measure:
SSSContributionEE :=
CALCULATE (
VALUES ( SSSContribution[EE] ),
FILTER (
SSSContribution,
[NMRPaySum] >= SSSContribution[Lower Bound] &&
[NMRPaySum] <= SSSContribution[Upper Bound]
)
)
However, I need the range lookup to only calculate if the employee type is satisfied.
The logic for it is below:
If Employee[Type]="Regular" Then
Calculate SSSConbtributionEE
Else
0
End If
I have tried this DAX formula, but doesn't seem to be working:
=
IF (
OR ( Salary[Type] = "Regular", Salary[Type] = "Agency" ),
CALCULATE (
VALUES ( SSSContribution[EE] ),
FILTER (
SSSContribution,
[NMRPaySum] >= SSSContribution[Lower Bound] &&
[NMRPaySum] <= SSSContribution[Upper Bound]
)
),
0
)
NMRPay Table:
SSS Contribution Table:
Employee Information Table:
Use your measure as is, for all the data. You then build a Pivot table, where you can use a filter or slicers on Employee Type to exclude unwanted values. Add the measure to the Values area and it will only calculate for data that is in the rows and columns of the pivot table.
For the OR condition, you should be able to add that as another filter:
= CALCULATE (
VALUES ( SSSContribution[EE] ),
FILTER (
SSSContribution,
[NMRPaySum] >= SSSContribution[Lower Bound] &&
[NMRPaySum] <= SSSContribution[Upper Bound]
),
FILTER (Salary, Salary[Type] = "Regular" || SalaryType = "Agency")
)
This may or may not work depending on your exact data model / relationship structure, but it might point you in the right direction. It's possible you need to use RELATED / RELATEDTABLE, but I'm not sure without being able to play with it myself.