SUM for previous Weeknum in Power BI - powerbi

Suppose we have a table
weeknum | revenue
------------------
12 | 10000
12 | 10000
12 | 10000
13 | 10000
13 | 10000
13 | 10000
14 | 10000
14 | 10000
I tried to calculate the sum of the revenue for the previous weeknum:
Previous Revenue =
CALCULATE(
SUM(Table1[revenue]),
FILTER(
ALL(Table1[weeknum]),
Table1[weeknum] = Table1[weeknum]-1
)
)
But, it is failed. Any Idea on this one

The statement you are passing to FILTER's FilterExpression needs to refer to the entry from Table1[weeknum] within the current row context.
This can be achieved by replacing
Table1[weeknum] = Table1[weeknum]-1
with
Table1[weeknum] = MIN(Table1[weeknum])-1
though it is perhaps better practice to create a variable, viz:
Previous Revenue :=
VAR ThisWeekNum =
MIN( Table1[weeknum] )
RETURN
CALCULATE(
SUM( Table1[revenue] ),
FILTER(
ALL( Table1[weeknum] ),
Table1[weeknum] = ThisWeekNum - 1
)
)

Related

Sum previous rows in column

I am looking for a solution to sum previous rows in a calculated column.
Sample data:
product | sales | cumulative
000001 | 2000 | 2000
000001 | 2000 | 4000
000002 | 1500 | 1500
000001 | 2000 | 6000
000002 | 1500 | 3000
Could anyone help me with the DAX please.
This is what I would do
step 1)
I would create a new ordinal column with a sequential number for each product group
index =
RANKX (
FILTER (
Sales,
EARLIER ( Sales[Product] ) = Sales[Product]
),
Sales[Sales],
,
ASC
)
Step 2)
I create the Running Totals column that shows the running totals by group
Running Totals =
CALCULATE (
SUM (Sales[Sales]),
FILTER(
Sales,
Sales[Product] = EARLIER ( Sales[Product])
&& Sales[index] <= EARLIER ( Sales[index])
)
)
this is the result

How to create dynamic child table with DAX in PowerBI

I have this table:
Order | Total | FirstPayment | Months
1 | 1000 | 2021-01-01 | 2
2 | 600 | 2021-02-01 | 3
And I need to create a another table with the installments, like this:
Month | Order | Value
2021-01-01 | 1 | 500
2021-02-01 | 1 | 500
2021-02-01 | 2 | 200
2021-03-01 | 2 | 200
2021-04-01 | 2 | 200
So, I want to create a child table with one row for each month of payment.
Please, can you help?
As per my comment, I would actually do it like this:
Create dates table that spans all dates between two ranges. You could actually filter it to contain only relevant dates for better performance, but I didn't bother (this is a table formula):
Payments = CALENDAR(MIN(Orders[FirstPayment]), MAXX(Orders, EDATE(Orders[FirstPayment], Orders[Months])))
Create a measure that would show appropriate values for relevant dates:
Payment amount =
SUMX (
Payments,
VAR d =
DAY ( Payments[Date] )
RETURN
SUMX (
FILTER (
Orders,
DAY ( Orders[FirstPayment] )
== d
&& Payments[Date] <= EDATE ( Orders[FirstPayment], Orders[Months] -1 )
&& Payments[Date] >= Orders[FirstPayment]
),
[Total] / [Months]
)
)
The result - based on Order from Orders table and Date from Payments table:
EDIT
Of course, it is also possible to do what you asked. You have to combine the two formulas to create a calculated table like this (below is a table formula that you apply when you select New table):
Installments =
SELECTCOLUMNS (
FILTER (
CROSSJOIN (
CALENDAR (
MIN ( Orders[FirstPayment] ),
MAXX ( Orders, EDATE ( Orders[FirstPayment], Orders[Months] ) )
),
Orders
),
[Date] >= [FirstPayment]
&& DAY ( [Date] ) = DAY ( [FirstPayment] )
&& [Date]
<= EDATE ( [FirstPayment], [Months] - 1 )
),
"Date", [Date],
"Order", [Order],
"Value", [Total] / [Months]
)

DAX get N'th last non-blank value

For any given date, I would like to get an average Sales of the most recent 3 days with non-blank sales. So I need to retrieve not only the last non-blank sales (which might be easy) but I also need to get the second last and third last sales. Generally, I need N'th last sales.
Sample data:
+------------+--------+--------+--------+--------+------------------+
| Date | Amount | N'th 1 | N'th 2 | N'th 3 | Expected Results |
+------------+--------+--------+--------+--------+------------------+
| 2021-02-01 | 1 | 1 | | | 1.00 |
| 2021-02-02 | 2 | 2 | 1 | | 1.50 |
| 2021-02-03 | 2 | 2 | 2 | 1 | 1.67 |
| 2021-02-04 | | 2 | 2 | 1 | 1.67 |
| 2021-02-05 | 3 | 3 | 2 | 2 | 2.33 |
| 2021-02-06 | | 3 | 2 | 2 | 2.33 |
| 2021-02-07 | | 3 | 2 | 2 | 2.33 |
| 2021-02-08 | 4 | 4 | 3 | 2 | 3.00 |
| 2021-02-09 | | 4 | 3 | 2 | 3.00 |
| 2021-02-10 | | 4 | 3 | 2 | 3.00 |
| 2021-02-11 | | 4 | 3 | 2 | 3.00 |
+------------+--------+--------+--------+--------+------------------+
The N'th 1 is the last "non-blank" sales. The N'th 2 is the "last but one". The expected result is the average of N1, N2, N3.
Link to sample data file with solutions suggested by accepted answer:
DAX Rolling Average NonBlanks.pbix
Here's my take (it's a measure):
Non-blank average =
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = FILTER(ALL(Data), NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate)
var rankedTab = FILTER ( ADDCOLUMNS ( nonBlankTab, "Rank", RANKX ( nonBlankTab, [Date] ) ), [Rank] <= 3 )
return AVERAGEX(rankedTab, [Amount])
EDIT:
Just an explanation:
the measure is calculated for the selected date. If no date context is present, the latest date is assumed.
Then I filter out the table to contain only rows with non blank sales not later than curDate
Then I rank the dates so that the latest 3 dates always receive ranks 1, 2 and 3.
Then I filter out all the dates with rank higher than 3
Finally, I calculate an average over the remaining 3 data points.
EDIT2:
I simplified the measure a bit - lastSalesDate is not necessary. Also, as per request in the comments, I left the first attempt as it was, and here is the modified version with TOPN instead of ADDCOLUMNS/RANKX/FILTER combo:
Non-blank average =
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = FILTER(ALL(Data), NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate)
var rankedTab = TOPN(3, nonBlankTab, [Date])
return AVERAGEX(rankedTab, [Amount])
EDIT3:
A more universal version of the measure that just removes filters from Date column, which is actually all we need. No need to butcher all the other filters on the table:
Non-blank average =
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = CALCULATETABLE(FILTER(Data, NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate), REMOVEFILTERS(Data[Date]))
var rankedTab = TOPN(3, nonBlankTab, [Date])
return AVERAGEX(rankedTab, [Amount])
Firs, create these below 3 measures-
n1 =
VAR current_date = MIN(your_table_name[Date])
VAR first_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)
RETURN
CALCULATE(
SUM(your_table_name[Amount]),
FILTER(
ALL(your_table_name),
your_table_name[Date] = first_max_date_with_no_blank
)
)
n2 =
VAR current_date = MIN(your_table_name[Date])
VAR first_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)
VAR second_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] < first_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)
RETURN
CALCULATE(
SUM(your_table_name[Amount]),
FILTER(
ALL(your_table_name),
your_table_name[Date] = second_max_date_with_no_blank
)
)
n3 =
VAR current_date = MIN(your_table_name[Date])
VAR first_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)
VAR second_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] < first_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)
VAR third_max_date_with_no_blank =
CALCULATE(
MAX(your_table_name[Date]),
FILTER(ALL(your_table_name), your_table_name[Date] < second_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)
RETURN
CALCULATE(
SUM(your_table_name[Amount]),
FILTER(
ALL(your_table_name),
your_table_name[Date] = third_max_date_with_no_blank
)
)
Now create this final measure-
average =
VAR sum_sales = [n1] + [n2] + [n3]
VAR devide_by = IF([n1] = BLANK(),0,1) + IF([n2] = BLANK(),0,1) + IF([n3] = BLANK(),0,1)
RETURN DIVIDE(sum_sales,devide_by)
Here is the final output-

Rolling average over time with multiple values per date

I'm trying to calculate a rolling average for each row of a table based on values present in this table based on a sliding time window looking ahead and back a certain amount of days.
Given the following table:
myTable
+------------+-------+
| Date | Value |
+------------+-------+
| 31/05/2020 | 5 |
+------------+-------+
| 31/05/2020 | 10 |
+------------+-------+
| 01/06/2020 | 50 |
+------------+-------+
| 01/08/2020 | 50 |
+------------+-------+
and the measure
myMeasure =
VAR LookAheadAndBehindInDays = 28
RETURN
AVERAGEX (
DATESINPERIOD (
myTable[Date],
DATEADD ( LASTDATE ( myTable[Date] ), LookAheadAndBehindInDays, DAY ),
-2 * LookAheadAndBehindInDays,
DAY
),
myTable[Value]
)
I checked that the DATESINPERIOD returns effectively the right dates. My problem lies in the calculation of the average.
Instead of calculating the average of all values directly (expected result)
+------------+-------+---------------------------+
| Date | Value | myMeasure |
+------------+-------+---------------------------+
| 31/05/2020 | 5 | (5 + 10 + 50) / 3 = 21.66 |
+------------+-------+---------------------------+
| 31/05/2020 | 10 | (5 + 10 + 50) / 3 = 21.66 |
+------------+-------+---------------------------+
| 01/06/2020 | 50 | (5 + 10 + 50) / 3 = 21.66 |
+------------+-------+---------------------------+
| 01/08/2020 | 27 | 27 / 1 = 27 |
+------------+-------+---------------------------+
It first calculates the average of each date, and then the average of those values:
+------------+-------+--------------------+------------------------+
| Date | Value | Avg. by Date | myMeasure |
+------------+-------+--------------------+------------------------+
| 31/05/2020 | 5 | (5 + 10) / 2 = 7.5 | (7.5 + 50) / 3 = 28.75 |
+------------+-------+--------------------+------------------------+
| 31/05/2020 | 10 | (5 + 10) / 2 = 7.5 | (7.5 + 50) / 3 = 28.75 |
+------------+-------+--------------------+------------------------+
| 01/06/2020 | 50 | 50 / 1 = 50 | (7.5 + 50) / 3 = 28.75 |
+------------+-------+--------------------+------------------------+
| 01/08/2020 | 27 | 27 / 1 = 27 | 27 / 1 = 27 |
+------------+-------+--------------------+------------------------+
I found out about this behavior by using this measure:
myMeasure DEBUG =
VAR LookAheadAndBehindInDays = 28
VAR vTable =
DATESINPERIOD (
myTable[Date],
DATEADD ( LASTDATE ( myTable[Date] ), LookAheadAndBehindInDays , DAY ),
-2 * LookAheadAndBehindInDays,
DAY
)
RETURN
FIRSTDATE ( vTable ) & " - " & LASTDATE ( vTable ) & UNICHAR(10)
& " - Row Count: " & COUNTROWS ( vTable ) & UNICHAR(10)
& " - Avg: " & AVERAGEX(vTable, myTable[Value]) & UNICHAR(10)
& " - Dates: " & CONCATENATEX ( vTable, myTable[Date], "," ) & UNICHAR(10)
& " - Values: " & CONCATENATEX ( vTable, myTable[Value], "," )
This returns for rows with the date '31/05/2020' and '31/05/2020' the following value:
31/05/2020 - 01/06/2020
Row Count: 2
Avg: 28.75
Dates: 31/05/2020,01/06/2020
Values: 7.5,50
Most notable are the Row Count 2, which I would expect to be 3 and the values 5,10 and 50 (as reflected above in the tables)
So my question is, how can in calculate the rolling average over time by weighting each value equally, instead of weighting each day equally.
I'm not sure I completely understood the problem, but to me you just need a standard AVERAGE and not the AVERAGEX iterator.
I've changed the formula a bit and didn't use DATESINPERIOD, this one achieves the same result and (to me) is more clear and readable
Avg =
VAR DaysInterval = 28
RETURN
CALCULATE (
AVERAGE ( myTable[Value] ),
DATESBETWEEN (
myTable[Date],
MAX ( myTable[Date] ) - DaysInterval, --from
MAX ( myTable[Date] ) + DaysInterval --to
)
)
here is the result (based on the sample dataset)
What you are looking for is the calculated average from the days -/+28:
myMeasure =
VAR LookAheadAndBehindInDays = 28
var curDAte = rolling[ Date]
return CALCULATE(AVERAGE(rolling[Value]),
FILTER(rolling,
rolling[ Date] +LookAheadAndBehindInDays >= curDAte &&
rolling[ Date] -LookAheadAndBehindInDays <= curDAte))
as you can see I am using the filter to get the rows falling in the date range and calculate the average over those.

How do I calculate the number of positive days?

I have the following measure:
no_positive_bets =
COUNTAX(
FILTER(
'belgarath match_',
'belgarath match_'[ogion_pnl] >= 0
),
'belgarath match_'[ogion_pnl]
)
Assuming there is a field called 'belgarath match_'[date] how would I group 'belgarath match_'[ogion_pnl] by day so that I can work out the number of positive days?
Edit:
By way of some sample data:
+-----+------------+-----------+
| id_ | date | ogion_pnl |
+-----+------------+-----------+
| 1 | 01/01/2020 | 100 |
| 2 | 02/01/2020 | 100 |
| 3 | 02/01/2020 | -50 |
| 4 | 03/01/2020 | 100 |
| 5 | 03/01/2020 | -150 |
+-----+------------+-----------+
The current snippet I have will return 3 because three rows are positive. However I would like it to return 2 as the first two days are positive.
Try this it may help..
no_positive_bets = COUNTAX(FILTER('belgarath match_', [ogion_pnl] >= 0), [ogion_pnl])
Create this below Custom Column First-
is possitive =
VAR current_date = your_table_name[date]
VAR current_date_sum =
CALCULATE(
SUM(your_table_name[ogion_pnl]),
FILTER(
ALL(your_table_name),
your_table_name[date] = current_date
)
)
RETURN IF(current_date_sum >= 0, 1, 0)
Now create this below Measure-
number of possitive day =
CALCULATE(
DISTINCTCOUNT(your_table_name[date]),
FILTER(
ALL(your_table_name),
your_table_name[is possitive] = 1
)
)
Now add the measure number of possitive day to a card and the output will be as below-