Monthly percentage of year [PowerBi] [Dax] - powerbi

I'm quite new to Power Bi and DAX in general and I have some problems calculating how much of each month was of the whole year.
Example:
Year 2021:
Month Value Percentage
Jan. 100 10
Feb. 50 5
Mar. 250 25
Apr. 30 3
Etc...
Total 1000 100
I have calculated the percentage column in dax as:
=
[Value] /
CALCULATE(
[Value],
ALLEXCEPT(Calendar, Calendar[Year])
)
This gives me the correct result for the chosen year, the problem I have is when trying to compare it to last year's result.
I've tried to add
"SAMEPERIODLASTYEAR(Calendar[Key_Calendar])" and "PARALLELLPERIOD(CALENDAR[Key_Calendar],-12,Month)"
but neither of them gives me the result I am looking for.
I'd appreciate any help that I can get on the issue.

First you need to create such a model:
If you want to create a simple calendar table, create new table and paste this code:
Calendar =
VAR BaseTable = CALENDAR(DATE(2020,01,01), DATE(2021,12,31))
RETURN
ADDCOLUMNS(
BaseTable,
"Year", YEAR([Date]),
"Month", MONTH([Date]),
"MonthName", FORMAT([Date],"mmm"),
"Quarter", QUARTER([Date]),
"Period", FORMAT([Date],"yyyy-mm")
)
Your resulting Date table:
Then create a fact table with some data:
Date Value
01/01/2021 100
01/02/2021 50
01/03/2021 250
01/04/2021 30
01/05/2021 25
01/06/2021 50
01/07/2021 65
01/08/2021 75
01/09/2021 70
01/10/2021 35
01/11/2021 40
01/12/2021 20
01/01/2020 10
01/02/2020 25
01/03/2020 65
01/04/2020 85
01/05/2020 35
01/06/2020 25
01/07/2020 35
01/08/2020 10
01/09/2020 30
01/10/2020 50
01/11/2020 30
01/12/2020 20
Then we can create 2 new measures!
Percentage =
DIVIDE(SUM(FactTable[Value]),CALCULATE(SUM(FactTable[Value]),ALL(FactTable)))
Percentage_LastYear =
CALCULATE(
[Percentage],
SAMEPERIODLASTYEAR('Calendar'[Date])
)
Then create a table visual and put it like you see in the below screenshot:
And you are Good to go! I hope It solves your problem!

Assuming that your Calendar dimension has a date column called Date, the following would get the value for the prior year:
Value PY =
CALCULATE ( [Value], SAMEPERIODLASTYEAR ( 'Calendar'[Date] ) )

Related

Latest values by category based on a selected date

First, as I am a French guy, I want to apologise in advance for my poor English!
Despite my searches since few days, I cannot find the correct measure to solve my problem.
I think I am close to the solution, but I really need help to achieve this job!
Here is my need:
I have a dataset with a date table and a "Position" (i.e. "stock") table, which is my fact table, with date column.
Classic relationship between these 2 tables. Many Dates in "Position" table / 1 date un "Dates" table.
My "Dates" table has a one date per day (Column "AsOf")
My "Deals" table looks like this:
Id
DealId
AsOfDate
Notional
10000
1
9/1/2022
2000000
10001
1
9/1/2022
3000000
10002
1
9/1/2022
1818147
10010
4
5/31/2022
2000000
10011
4
5/31/2022
997500
10012
4
5/31/2022
1500000
10013
4
5/31/2022
1127820
10014
5
7/27/2022
140000
10015
5
7/27/2022
210000
10016
5
7/27/2022
500000
10017
5
7/27/2022
750000
10018
5
7/27/2022
625000
10019
1
8/31/2022
2000000
10020
1
8/31/2022
3000000
10021
1
8/31/2022
1801257
10022
1
8/31/2022
96976
10023
1
8/31/2022
1193365
10024
1
8/31/2022
67883
Based on a selected date (slicer with all dates from "Dates" table), I would like to calculate the sum of Last Notional for each "Deal" (column "DealId").
So, I must identify, for each Deal, the last "Asof Date" before or equal to the selected date and sum all matching rows.
Examples:
If selected date is 9/1/2022, I will see all rows, except rows asof date = 8/31/2022 for deal 1 (as the last date for this deal is 9/1/2022).
So, I expect to see:
DealId Sum of Notional
1 6 818 147
4 5 625 320
5 2 225 000
Grand Total 14 668 467
If I select 8/31/2022, total for Deal 1 changes (as we now take rows of 8/31 instead of 1/9):
DealId Sum of Notional
1 8 159 481
4 5 625 320
5 2 225 000
Grand Total 16 009 800
If I select 7/29, only deals 4 and 5 are active on this date, so the results should be:
DealId Sum of Notional
4 5 625 320
5 2 225 000
Grand Total 7 850 320
I think I found a solution for the rows, but my total is wrong (only notionals of the selected date are totalized).
I also think my measure is incorrect if I try to display the notional amounts aggregated by Rating (other column in my table) instead of deal.
Here is my measure:
Last Notional =
VAR SelectedAsOf =
SELECTEDVALUE ( Dates[AsOf] )
VAR LastAsofPerDeal =
CALCULATE (
MAX ( Deals[AsOf Date] ),
FILTER ( ALLEXCEPT ( Deals, Deals[DealId] ), Deals[AsOf Date] <= SelectedAsOf )
)
RETURN
CALCULATE (
SUM ( Deals[Notional] ),
FILTER (
ALLEXCEPT ( Deals, Deals[DealId]),
LastAsofPerDeal = Deals[AsOf Date]
)
)
I hope it is clear for you, and you will be able to find a solution for this.
Thanks in advance.
Antoine
Make sure you have no relationship between your calendar table and deals table like so.
Create a slicer with your dates table and create a table visual with deal id. Then add a measure to the table as follows:
Sum of Notional =
VAR slicer = SELECTEDVALUE(Dates[Date])
VAR tbl = FILTER(Deals,Deals[AsOfDate] <= slicer)
VAR maxBalanceDate = CALCULATE(MAX(Deals[AsOfDate]),tbl)
RETURN
CALCULATE(
SUM(Deals[Notional]),
Deals[AsOfDate] = maxBalanceDate
)

Creating a calculated field in Power BI

I have a tricky PowerBI problem that I'm hoping for some help with.
The data are as follows:
Product
Year
Purchases
'Book'
2020
24
'Book'
2021
15
'Book'
2022
10
'TV'
2020
42
'TV'
2021
48
'TV'
2022
33
'PC'
2020
130
'PC'
2021
115
'PC'
2022
170
I need help firstly making a calculated field that shows the percentage of growth/decline in each category year on year for the two most recent years (2021 and 2022 in this case). The change should be calculated as follows:
=(MostRecentYear - PreviousYear)/PreviousYear
2021 and 2022 can be specified if required, but would prefer to use MAX and MAX-1 to determine it so that I don't need to update code every year. If that's possible of course... It would also be great if the result can be expressed as a percentage and limited to one decimal place as per the table below.
Secondly, I need to include all these data in a matrix in the following format:
Product
2020
2021
2022
% Change
'Book'
24
15
10
-33.3%
'TV'
42
48
33
-31.3%
'PC'
130
115
170
47.8%
Thanks in advance.
Define the following three measures:
Total_Purchases =
SUM ( 'Table'[Purchases] )
% Change =
VAR Most_Recent_Year =
CALCULATE (
MAX ( 'Table'[Year] ),
ALL ( 'Table'[Year] )
)
VAR Previous_Year = Most_Recent_Year - 1
VAR Purchases_Most_Recent_Year =
CALCULATE (
[Total_Purchases],
'Table'[Year] = Most_Recent_Year
)
VAR Purchases_Previous_Year =
CALCULATE (
[Total_Purchases],
'Table'[Year] = Previous_Year
)
RETURN
DIVIDE (
Purchases_Most_Recent_Year - Purchases_Previous_Year,
Purchases_Previous_Year
)
2020 =
CALCULATE ( [Total_Purchases], 'Table'[Year] = 2020 )
Duplicate the last measure as required for other relevant years. Add all measures to a standard table visual.

How to get a percentage of grouped values over a period of time (at the hour scale) in DAX?

I have a dataset containing the duration (in minutes) of occupancy events over a period of 1 hour in my rooms:
# room date duration
--- ---- ------------------- --------
0 A1 2022-01-01 08:00:00 30
1 A1 2022-01-01 10:00:00 5
2 A1 2022-01-01 16:00:00 30
3 A1 2022-01-02 10:00:00 60
4 A1 2022-01-02 16:00:00 60
...
My date column is linked to a date table in which I have:
# datetime year month monthName day dayOfWeek dayName hour
--- ------------------- ---- ----- --------- --- --------- -------- ----
...
k 2022-01-01 08:00:00 2022 1 January 1 5 Saturday 8
k+1 2022-01-01 09:00:00 2022 1 January 1 5 Saturday 9
...
n 2022-03-01 22:00:00 2022 3 March 1 1 Tuesday 22
I am trying to retrieve the following percentage: duration/timeperiod through a measure. The idea behind using a measure is :
Being able to use a time slicer and see my percentage being updated
Using, for example, a bar chart with my date hierarchy, and being able to see a percentage in my different level of hierarchy (datetime -> year -> month -> dayOfWeek -> hour)
Attempt
My idea was to create a first measure that would return the number of minutes between the first and the last date currently chosen. Here is what I came up with:
Diff minutes = DATEDIFF(
FIRSTDATE( 'date'[date] ),
LASTDATE( 'date'[date] ),
MINUTE
)
The idea was then to create a second measure that would divide the SUM of the durations by the Diff minutes' measure:
My rate = DIVIDE(
SUM( 'table'[duration] ),
[Diff minutes]
)
I currently face a few issues:
The slicer is set to (2022-01-02 --> 2022-01-03) and if I check in a matrix, I have datetime between 2022-01-02 0:00:00 and 2022-01-03 23:00:00, but my measure returns 1440 which is the number of minutes in a day but not in my selected time period
The percentage is also wrong unfortunately. Let's take the example that I highlighted in the capture. There are 2 values for the 10h slot, 5min and 60min. But the percentage shows 4.51% instead of 54.2%. It actually is the result of 65/1440, 1440 being the total of minutes for my whole time period, not my 10h slot.
Examples
1- Let's say I have a slicer over a period of 2 days (2022-01-01 --> 2022-01-02) and my dataset is the one provided before:
I would have a total duration of 185 minutes (30+5+30+60+60)
My time period would be 2 days = 48h = 2880 minutes
The displayed ratio would be: 6.4% (185/2880)
2- With the same slicer, a matrix with hours and percentage would give me:
hour rate
---- -----
0 0.0%
1 0.0%
...
8 25.0% <--- 30 minutes on the 1st of January and 0 minutes on the 2nd
9 0.0% <--- (5+0)/120
10 54.2% <--- (5+60)/120
...
16 75.0% <--- (30+60)/120
Constraints
The example I provided only has 1 room. In practice, there are n rooms and I would like my measure to return the percentage as the mean of all my rooms.
Would it be possible ? Have I chosen the right method ?
The DateDiff function you have created should work, I have tested it on a report and when I select some dates, it gives me the difference between the first and last selected dates.
Make sure your slicer is interacting with the measure.
In the meantime, I think I found a simpler and easier way to do it.
First, I added a new column to my date table, that seems dubious but is actually helpful:
minutes = 60
This allows me to get rid of the DATEDIFF function. My rate measure now looks like this:
My rate = DIVIDE(
SUM( table[duration] ),
[Number of minutes],
0
)
Here, I use the measure Number of minutes which is simply a SUM of the values in the minutes column. In order to provide accurate results when I have multiple rooms selected, I multiplied the number of minutes by the number of rooms:
Number of minutes = COUNTROWS( rooms ) * SUM( 'date'[minutes] )
This now works perfectly with my date hierarchy!

Power BI | circumvent "Expressions that yield variant data-type cannot..." when adding a calculated column to a summarized table

Again.
Sorry to bother, but currently, I'm trying to estimate the size of a call center, which of course, requires calculating some parameters for the Erlang-A distribution. At this time, I want to get the Average Time to Abandon, which, in fact, is the median of the abandon time, or, the abandon time up to which the lower half the abandoned calls are abandoned.
TABLE A is the result of a SELECTCOLUMN function that yields:
TABLE A
Call ID
date
YEAR
MONTH
WEEK OF THE YEAR
DAY OF THE WEEK
TIME BAND
SERVICE
TIME BEFORE ABANDON
asdf1
19-apr-2021
2021
4
17
1
11 hrs
INFO
49
asdf8
26-apr-2021
2021
4
18
1
16 hrs
INFO
57
asdf7
26-apr-2021
2021
4
18
1
16 hrs
INFO
85
asdf5
26-apr-2021
2021
4
18
1
08 hrs
INFO
103
asdf2
20-apr-2021
2021
4
17
2
12 hrs
APPOINTMENT
123
asdf4
26-apr-2021
2021
4
18
1
09 hrs
INFO
176
asdf3
26-apr-2021
2021
4
18
1
13 hrs
HOTLINE
224
asdf6
26-apr-2021
2021
4
18
1
16 hrs
INFO
296
Call ID is unique.
What I want to do is to calculate the median, for any number of "filters" combination.
For example, the GENERAL median should be 103 seconds, but, if I focus only on the calls that took place in the 16 hrs time band, the median is 85 seconds
TABLE B was created with the SUMMARIZE function applied on TABLE A. So, from TABLE A sample, TABLE B
TABLE B
SERVICE
YEAR
MONTH
WEEK OF THE YEAR
DAY OF THE WEEK
TIME BAND
-
fully filtered MEDIAN PATIENCE
MEDIAN PATIENCE (service only)
GENERAL MEDIAN PATIENCE
INFO
2021
4
18
1
16
-
85
85
103
INFO
2021
4
18
1
08
-
103
85
103
INFO
2021
4
18
1
09
-
176
85
103
INFO
2021
4
17
1
11
-
49
85
103
APPOINTMENT
2021
4
18
2
12
-
123
123
103
HOTLINE
2021
4
18
1
13
-
224
224
103
From SERVICE to TIME Band, it's the summarize part. Afterwards, it's the median(s) columns
What I want is to add the medians columns. However, for the fully filtered median, I'm attempting to do so with the code:
fully median patience = CALCULATE(MEDIAN('TABLE A'[TIME BEFORE ABANDON]), FILTER('TABLE A', 'TABLE A'[SERVICE] = 'TABLE B'[SERVICE] && 'TABLE A'[YEAR] = 'TABLE B'[YEAR] && 'TABLE A'[MONTH] = 'TABLE B'[MONTH] && 'TABLE A'[DAY OF THE WEEK] = 'TABLE B'[DAY OF THE WEEK] && 'TABLE A'[TIME BAND] = 'TABLE B'[TIME BAND]))
But I'm getting the message: "Expressions that yield variant data-type cannot be used to define calculated columns."
Which seems weird to me, since the function countrows works just fine within a CALCULATE, and applied to a bunch of summarized columns.
As a matter of fact, I can get the median with a MEASURE, insert it in a CARD VISUAL, and I only have to add the filters to it. Or add many slicers to a dashboard page. But still, It would be better to get medians in the TABLE in order visualize many medians at the time.
Any suggestions?
You result must contain some blanks that's why you are getting the error, do explicit conversion with CONVERT
fully median patience =
CONVERT (
CALCULATE (
MEDIAN ( 'TABLE A'[TIME BEFORE ABANDON] ),
FILTER (
'TABLE A',
'TABLE A'[SERVICE] = 'TABLE B'[SERVICE]
&& 'TABLE A'[YEAR] = 'TABLE B'[YEAR]
&& 'TABLE A'[MONTH] = 'TABLE B'[MONTH]
&& 'TABLE A'[DAY OF THE WEEK] = 'TABLE B'[DAY OF THE WEEK]
&& 'TABLE A'[TIME BAND] = 'TABLE B'[TIME BAND]
)
),
INTEGER
)

DAX: Calculate only when data is present for all years in dataset

I have a data set that contains sales forecast data by year over 5 years.
Each row has customer, item type, year, qty and sales price.
Not all customers buy all products in all years.
I want to get a list of all products that are purchased in all of the listed years.
An example, cut-down table looks like this:
Customer Product Year Qty Price
CustA ProdA 2020 50 100
CustA ProdA 2021 50 100
CustA ProdA 2022 50 100
CustA ProdB 2020 50 100
CustA ProdB 2021 50 100
CustA ProdC 2021 50 100
CustA ProdC 2022 50 100
CustA ProdD 2020 50 100
CustA ProdD 2021 50 100
CustA ProdD 2022 50 100
CustB ProdA 2021 50 100
CustB ProdA 2022 50 100
CustB ProdC 2020 50 100
CustB ProdC 2021 50 100
CustB ProdC 2022 50 100
CustB ProdD 2020 50 100
CustB ProdD 2021 0 100
CustB ProdD 2022 50 100
And transposed, looks like this:
Customer Product 2020 2021 2022
CustA ProdA 50 50 50
CustA ProdB 50 50
CustA ProdC 50 50
CustA ProdD 50 50 50
CustB ProdA 50 50
CustB ProdC 50 50 50
CustB ProdD 50 0 50
So, for this example, I'd want to do calculations on, or indicate rows that have a sales qty for all three years. I was trying to use the following formula which I would have compared with the max number of years in the set to mark a row as valid or not, but it's killing Excel. There are only 32,000 rows in the source table.
=CALCULATE(
DISTINCTCOUNT(DataTable[Year]),
filter(DataTable, DataTable[Product] = EARLIER(DataTable[Product])),
filter(DataTable, DataTable[Customer] = EARLIER(DataTable[Customer])),
filter(DataTable, DataTable[Qty] > 0)
)
Is there a better approach I could use for this?
How about this?
ProductList =
VAR AllYears = DISTINCTCOUNT ( 'DataTable'[Year] )
VAR Summary =
SUMMARIZE (
'DataTable',
'DataTable'[Product],
"YearsPurchased", CALCULATE (
DISTINCTCOUNT ( 'DataTable'[Year] ),
'DataTable'[Qty] > 0
)
)
RETURN
SELECTCOLUMNS (
FILTER ( Summary, [YearsPurchased] = AllYears ),
"Product", [Product]
)
The Summary aggregates at the Product level and looks at how many distinct years it had with non-zero quantity. Then you just filter for the ones that match AllYears and take the Product column.
Note that this returns a single column table and thus doesn't work as a calculated column or measure but a list is what you asked for.
Edit: To get the YearsPurchased as a calculated column, you just need part of this:
YearsPurchased =
CALCULATE (
DISTINCTCOUNT ( 'DataTable'[Year] ),
FILTER ( ALLEXCEPT ( 'DataTable', 'DataTable'[Product] ), 'DataTable'[Qty] > 0 )
)
You dont need to use dax to achieve this. Create a matrix visualization using the needed data.
It should looks like this:
Remember to disable the total and subtotal options.
This is other solution using a new column so you dont have to expand the matrix.
Column = COMBINEVALUES( " ", Table[Customer], Table[Product] )
Hope it helps you.