Powerbi: How to calculate average value per hour from value in minutes? - powerbi

So I am building a report that shows the time spent on a job and the income the job has generated. My boss wants to see the average income of a job in hours.
Let's say three jobs have been completed:
Job A: Time: 12 minutes & income 450 euro
Job B: Time: 24 minutes & income 600 euro
Job C: Time: 38 minutes & income 950 euro
Job D: Time: 82 minutes & income 1800 euro
How do i calculate the average income per hour in PowerBI/DAX?

If you want to do it in a structured way:
DEFINE
TABLE Payroll = SELECTCOLUMNS ({
("Job-A",FORMAT(TIME(00,12,00),"HH:MM:SS"),450),
("Job-B",FORMAT(TIME(00,24,00),"HH:MM:SS"),600),
("Job-C",FORMAT(TIME(00,38,00),"HH:MM:SS"),950),
("Job-D",FORMAT(TIME(00,82,00),"HH:MM:SS"),1800)
},"Type",[Value1],"Duration",[Value2],"Income",[Value3])
EVALUATE
Payroll
Final Code:
EVALUATE
ROW (
"AVG_Earnings",
FORMAT (
ROUND (
AVERAGEX (
ADDCOLUMNS (
ADDCOLUMNS (
Payroll,
"Hour", HOUR ( Payroll[Duration] ),
"Minute", MINUTE ( Payroll[Duration] ),
"Seconds", SECOND ( Payroll[Duration] )
),
"Total",
ROUND ( [Hour] + DIVIDE ( [Minute], 60 ) + DIVIDE ( [Seconds], 3600 ), 4 )
),
DIVIDE ( [Income], [Total] )
),
2
),
"Currency",
"de-DE"
)
)

Related

Need a DAX expression to calculate Rate of Success

I have a table called Payment_Methods in PBI with the following columns:
timestamp, weekDay, Hour, eventType, SuccessEvents, FailedEvents, addPymntCardInstance.
weekDay is ['Sunday', 'Monday', ..., 'Friday', 'Saturday']
Hour is [0, 1, 2, 3, ..., 21, 22, 23]
I want to create a PymntSuccessRate using the DAX expression below, but the results are always the same all the way down across the column PymntSuccessRate. How can I fix this. Appreciate if you can give me some clue. Thanks.
PymntSuccessRate =
DIVIDE(
SUMX(
FILTER(
GROUPBY(
Payment_Methods,
Payment_Methods[timestamp], Payment_Methods[weekDay], Payment_Methods[Hour]
),
Payment_Methods[eventType] = "Success"
),
SUM( Payment_Methods[addPymntCardInstance] )
),
SUMX(
GROUPBY(
Payment_Methods,
Payment_Methods[timestamp], Payment_Methods[weekDay], Payment_Methods[Hour]
),
SUM( Payment_Methods[addPymntCardInstance] )
)
)
timestamp
weekDay
Hour
SuccessEvents
FailedEvents
SuccessRate
2023-01-20
Friday
20
2
8
0.20
2023-01-20
Friday
19
121
111
0.52
2023-01-17
Tuesday
6
31
8
0.79
2023-01-17
Tuesday
5
19
14
0.57
based on your sample you don't need to use SUMX and GROUPBY (visual will do the grouping), this should be enough (used as a measure, NOT a calculated column):
PymntSuccessRate =
DIVIDE (
CALCULATE (
SUM ( Payment_Methods[addPymntCardInstance] ),
Payment_Methods[eventType] = "Success"
),
SUM ( Payment_Methods[addPymntCardInstance] )
)

calculate the difference between first and last value of each Id and count those with 10% decrease in DAX Power BI

have a simple table like this
ID value date
A 100 2020-01-01
B 80 2019-01-01
A 90 2022-01-01
A 130 2021-01-01
B 100 2021-01-01
and want to know how many IDs had 10% increase within a selected time period, IDs might not necessarily have an entry on Min(Date) or Max(Date), I'd like to know the difference between first and last value within the selected time period
I came up with something like this but not sure if it's working :
Measure=
Var FirstValue=
SUMX (
VALUES( table [ID] ),
CALCULATE ( MIN ( table[value]), FIRSTDATE ( 'Date'[DATE] ) )
)
Var LastValue =
SUMX (
VALUES( table[ID] ),
CALCULATE ( MIN ( table[value] ), LASTDATE ( 'Date'[DATE]) )
)
Return sumx(table,if( (FirstValue -LastValue )/FirstValue> 0.1 , 1,0)
)

Matching dates with weekdays, PowerBI

I have 2 tables, AvailabilitiesDB and AvailabilityTemplateDB.
The AvailabilitiesDB table looks like like
IsAvailable StartTime FinishTime Employee_ID Week Day Of the Week
1 25-09-2020 16:00:00 25-09-2020 19:00:00 101 39 5
0 27-08-2020 14:00:00 27-08-2020 17:00:00 13 35 4
1 25-11-2020 09:00:00 25-11-2020 18:00:00 66 48 3
The AvailabilityTemplateDB table looks like this:
Day Of The Week StartTime FinishTime Employee_ID
3 18:00:00 21:00:00 101
2 11:00:00 17:00:00 13
6 06:00:00 20:00:00 66
Here is the issue:
I want to calculate the availability of the employees, meaning their minutes available (so from StartTime to FinishTime).
However, the thing is: The employees all have a template (AvailabilityTemplateDB) which is their go-to work schedule, so if there is not any observations in AvailabilitiesDB, it means that they use their template. But if there is an observation for a specific employee in the AvailabilitiesDB, it means that the template has been overwritten for the specific day. The templates are recurrent every week, which is why they don't have specific dates, and just "Day of the Week".
So I want to calculate something along the lines of: calculate DatesBetween (Minutes), where employee id = employee id, and if there is a data in the availabilitiesDB it must use this number, so for the first observation it would be 180 minutes, but if there is not a date in there, it must take the time from the template table. I find this hard because all I have is "Day of the week" in the template table, and I don't know how i would "convert" it to dates.
This was what I have tried (Not near end result) and obviously it's not supposed to count rows, I was just trying in order to come closer to an answer. Date refers to my date table, which holds unique dates for all of the dates from the AvailabiltiesDB table.
Try =
VAR dates =
DATESBETWEEN (
'Date'[Date].[Date],
MIN ( 'Date'[Date].[Date] ),
MAX ( 'Date'[Date].[Date] )
)
VAR Employee_ID = AvailabilitiesDB[Employee_ID]
VAR Weekdays = AvailabilitiesDB[Day Of the Week]
VAR weekdaysAndDateMatch =
VAR COUNTZ =
CALCULATE (
COUNTROWS ( AvailabilitiesDB ),
FILTER (
AvailabilityTemplateDB,
Weekdays = AvailabilityTemplateDB[Day of the week]
&& Employee_ID = AvailabilityTemplateDB[Employee_ID]))
RETURN IF ( COUNTZ = 0, "Yes", "No" )
My desired outcome would be a column in the AvailabilitiesDB table that summed the availability in minutes per week, for every employee_ID.
I hope you can help me further, thank you in advance.
Events with a duration are simplified by implementing a snapshot table.
Another good practice when dealing with time is to split the date part and the time part in two different columns
So I created a small model with dimension Date, Employees and Time
For this example we just need the months from August to November. To match the Day of the week with the sample data I had to subtract 1.
Date =
ADDCOLUMNS (
CALENDAR ( "2020-08-01", "2020-11-30" ),
"WeekDay", WEEKDAY ( [Date] ) - 1
)
The Employees dimension is
Employees =
ADDCOLUMNS (
DISTINCT ( AvailabilitiesTemplateDB[Employee_ID] ),
"Name", FORMAT ( [Employee_ID], "000" )
)
For the time dimension I created a measure as a parameter with the time granularity to be used also for the snapshot table. This can be changed to adapt the model to the requirements.
To keep a low number of lines for this example I used a 1 hour interval
TimeInterval = VALUE( "01:00:00" )
So the Time table becomes
Time =
SELECTCOLUMNS (
GENERATESERIES ( VALUE ( "00:00:00" ), VALUE ( "23:59:59" ), [TimeInterval] ),
"Time", [Value]
)
The snapshot table is a table containing a row per each time interval for which an employee is available. To build this table we can use the set functions UNION and EXCEPT. The snapshot table has just three columns: the Employee_ID, the Date and the Time
This code matches the Date with the weekday using the Date table we build before
AvailabilitiesSnapshot =
VAR TimeGranularity = [TimeInterval]
VAR AvailableFromTemplateDB =
SELECTCOLUMNS(
GENERATE(
AvailabilitiesTemplateDB,
VAR DayOfWeek = AvailabilitiesTemplateDB[Day Of The Week]
VAR TimesTable =
SELECTCOLUMNS(
GENERATESERIES(
AvailabilitiesTemplateDB[StartTime],
AvailabilitiesTemplateDB[FinishTime] - TimeGranularity,
TimeGranularity
),
"Time", [Value]
)
RETURN
GENERATE(
FILTER( ALLNOBLANKROW( 'Date' ), 'Date'[WeekDay] = DayOfWeek ),
TimesTable
)
),
"Employee_ID", [Employee_ID],
"Date", [Date],
"Time", [Time]
)
VAR AvailableFromDB =
SELECTCOLUMNS(
GENERATE(
CALCULATETABLE( AvailabilitiesDB, AvailabilitiesDB[IsAvailable] = 1 ),
VAR TimesTable =
SELECTCOLUMNS(
GENERATESERIES(
AvailabilitiesDB[StartTimeOnly],
AvailabilitiesDB[FinishTimeOnly] - TimeGranularity,
TimeGranularity
),
"Time", [Value]
)
RETURN
TimesTable
),
"Employee_ID", [Employee_ID],
"Date", [Date],
"Time", [Time]
)
VAR UnavailableFromDB =
SELECTCOLUMNS(
GENERATE(
CALCULATETABLE( AvailabilitiesDB, AvailabilitiesDB[IsAvailable] = 0 ),
VAR TimesTable =
SELECTCOLUMNS(
GENERATESERIES(
AvailabilitiesDB[StartTimeOnly],
AvailabilitiesDB[FinishTimeOnly] - TimeGranularity,
TimeGranularity
),
"Time", [Value]
)
RETURN
TimesTable
),
"Employee_ID", [Employee_ID],
"Date", [Date],
"Time", [Time]
)
RETURN
EXCEPT(
DISTINCT( UNION( AvailableFromTemplateDB, AvailableFromDB ) ),
UnavailableFromDB
)
In this code first we add all available intervals, then we remove the intervals that are marked as not available, those with AvailabilitiesDB[IsAvailable] = 0
Then we create the relationships between this new snapshot table and the dimensions, to get the model
with this model, writing a measure to compute the available minutes is straigthforward
AvailableTime = COUNTROWS( AvailabilitiesSnapshot ) * [TimeInterval] * 24 * 60
The TimeInterval parameter can be changed to rise the detail level. Of course this will increase the number of rows of the snapshot table and also depends on the size of the input tables.

Show total Minute Utilization for An hour in PowerBI report

I am trying to do log(ssrs execution log) analysis is powerbi. Requirement here is to show how many minutes utilized for a particular hour based on the request start & end time. Below is example for 4 requests Start & end time with expected result.
1st request 12:00 AM - 12:15 AM
2nd request 12:05 AM - 12:10 AM
3rd request 12:40 AM - 12:42 AM
4th request 12:41 AM - 12:48 AM
So total minute utilization for 12 AM hour should be 15mins(as first two requests overlap with each other) + 8mins (as last two also overlap for some mins) = 23 mins of total utilization at 12 AM.
Any help will be greatly appreciated.
I'd recommend splitting up the hour into 60 minutes and counting how many of the minutes are within the time frame of one of the requests.
Something like this logic for a calculated column:
Utilization =
VAR CurrentHour = HOUR ( Requests[Start] )
VAR Minutes =
GENERATESERIES (
TIME ( CurrentHour, 0, 0 ),
TIME ( CurrentHour + 1, 0, 0 ),
TIME ( 0, 1, 0 )
) /*This generates a column named [Value] with 61 rows
starting from the beginning of the hour.*/
RETURN
SUMX (
Minutes,
IF (
COUNTROWS (
FILTER (
Requests,
HOUR ( Requests[Start] ) = CurrentHour
&& Requests[Start] < [Value]
&& Requests[End] > [Value]
)
) > 0,
1,
0
)
)

Number of Persons above the Mean

I have this simple data set from Excel:
Date Person Amount
Jan-18 jason 1
Jan-18 fred 2
Jan-18 george 3
Feb-18 jason 10
Feb-18 fred 12
Feb-18 george 15
Feb-18 jim 25
I added two measures:
Amount = SUM( Data[Amount] )
and
Average Amount per Person =
AVERAGEX(
VALUES( Data[Person]),
[Amount]
)
This works as I expect and is dynamic when I select a specific Date:
What I now want is "Number of Persons Above Average" - so in the screenshot only Jim is above 15.50 so the measure should return 1.
My attempt at this measure is this:
Number of Persons Above Average =
CALCULATE(
DISTINCTCOUNT( Data[Person] ),
FILTER(
Data,
SUM( Data[Amount] ) >= [Average Amount per Person]
)
)
As you can see below it just returns the number of persons displayed - in this case 4
How do I amend the above measure to the correct DAX ?
I like to use variables in situations like these:
Number of Persons Above Average =
VAR AveragePerPerson = [Average Amount per Person]
RETURN
CALCULATE ( DISTINCTCOUNT ( Data[Person] ),
Data[Amount] >= AveragePerPerson )
This way you don't have to worry about how the average measure will be computed inside of the CALCULATE and you don't have to use a FILTER function.