Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Compete to become Power BI Data Viz World Champion! First round ends August 18th. Get started.

Reply
PGG79
Frequent Visitor

PowerBI Model time dependant

Hi

I have two tables.

In one I have the technicians' hours recorded on a date, here is the example:

TechnicianRecording dateHours recorded
 Tech1    2023/01/01   8     
 Tech2    2023/01/02   7     
 Tech1    2023/01/03   6     
 Tech3    2023/01/04   5     
 Tech4    2023/02/01   7     
 Tech1    2023/02/01   8     
 Tech2    2023/02/02   7     
 Tech1    2023/02/03   6     
 Tech1    2023/03/03   5     

In the other table I have the technicians and their working schedule active from an specific date (hours, costs, conditions,... are different depending on the calendar), here is the example:

TechnicianWorking ScheduleActive since
 Tech1    Calendar1           2023/01/01   
 Tech2    Calendar2           2023/01/02   
 Tech3    Calendar3           2023/01/03   
 Tech1    Calendar2           2023/01/01   
 Tech4    Calendar3           2023/02/01   

I want to create a Power BI model that allows me to generate a report where I can see the recorded hours of the technicians, and the working schedule active on that moment.

Probably it is an easy solution but i cannot come up with it. Thank you so much!

1 ACCEPTED SOLUTION
v-sathmakuri
Community Support
Community Support

Hi @PGG79 ,

 

Thank you for reaching out to Microsoft Fabric Community.

 

Thank you @lbendlin  and @SundarRaj  for the response.

 

I have worked on your sample data and attached the PBIX file with the results. Please review it and let us know if it is helpful. If you have any further questions, please provide more details.

 

If this post helps, then please consider Accepting as solution to help the other members find it more quickly, don't forget to give a "Kudos" – I’d truly appreciate it! 

 

Thank you!!

View solution in original post

13 REPLIES 13
v-sathmakuri
Community Support
Community Support

Hi @PGG79 ,

 

I hope the information provided is helpful. Feel free to reach out if you have any further questions or would like to discuss this in more detail. If responses provided answers your question, please accept it as a solution so other community members with similar problems can find a solution faster.

 

Thank you!!

v-sathmakuri
Community Support
Community Support

Hi @PGG79 ,

 

I wanted to check if you had the opportunity to review the information provided. Please feel free to contact us if you have any further questions. If the responses has addressed your query, please accept it as a solution and give a 'Kudos' so other members can easily find it.

 

Thank you!!

v-sathmakuri
Community Support
Community Support

Hi @PGG79 ,

 

May I ask if you have resolved this issue? If so, please mark the helpful reply and accept it as the solution. This will be helpful for other community members who have similar problems to solve it faster.

 

Thank you.

v-sathmakuri
Community Support
Community Support

Hi @PGG79 ,

 

Thank you for reaching out to Microsoft Fabric Community.

 

Thank you @lbendlin  and @SundarRaj  for the response.

 

I have worked on your sample data and attached the PBIX file with the results. Please review it and let us know if it is helpful. If you have any further questions, please provide more details.

 

If this post helps, then please consider Accepting as solution to help the other members find it more quickly, don't forget to give a "Kudos" – I’d truly appreciate it! 

 

Thank you!!

SundarRaj
Super User
Super User

Hi @PGG79 , is this what you are looking for? I'll attach the images of the output and M code used. Let me know if I understood your query correctly. Thanks!

SundarRaj_0-1744750453326.png

SundarRaj_1-1744750479407.png

Here's the code:
let
Source = Excel.CurrentWorkbook(){[Name = "Table5"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Technician", type text}, {"Recording date", type date}, {"Hours recorded", Int64.Type}}),
LookUp = Table.AddColumn(#"Changed Type","LookUpVal",each [Technician] & "-" & Text.From([Recording date])),
Table = Excel.CurrentWorkbook(){[Name = "Table6"]}[Content],
Type = Table.TransformColumnTypes(Table,{{"Technician", type text}, {"Working Schedule", type text}, {"Active since", type date}}),
Position = Table.AddColumn(Type,"HoursRecorded",each List.PositionOf(LookUp[LookUpVal],[Technician] & "-" & Text.From([Active since]))),
#"Recorded Hours" = Table.TransformColumns(Position,{"HoursRecorded", each try LookUp{_}[Hours recorded] otherwise null})
in
#"Recorded Hours"

Sundar Rajagopalan

Hi @SundarRaj 
thank you for the quick answer and for the idea, but that solution is based on a vlookup and that means that if the match of "technician+startdate" with "technician+recording date" is not exact, the result is "null". Please check the answer i have given to Ibendlin that contains more details because when i did the first post it was a shorten example but the tables have more fields. Thank you for your support!

lbendlin
Super User
Super User

Your sample data is not clear to me.  What would be the expected outcome based on the sample data you provided?

Hi @lbendlin 

When I posted the question it was with a short example, I try to explain it a bit better. I also add another table I have.

- I have Technicians (TechniciansDetails). The information of the Technicians can be updated at any time. The information is: Organization to where they belong to, the job position, the costarea to where they belong....
For each change in the information of a Technician, there is a record with "start" and "end date" in the table. The active one is the one with "end date = 31/12/999".

- The Technicians can work based on different Working Schedules (TechnicianWorkingSchedule). The working schedule of the Technicians can be updated at any time. Each time a Technician changes Working Schedule, there is a record with "start" and "end date". The active one is the one with "end date = 31/12/999".

- The Technicians record the times they spent per working day in each topic (7 hours of work, 1 hour of travel, 1 hour of lunch,...) (TechnicianHoursRecorded). For each working day the technicians record: their hours, in which project, ... For each time recorded, there is an entry in the table with the date when the entry was done.

 

--> It could be that for each working day, the technician have a different job position or a different calendar.

I need to have a model that helps me to report by working day, the recording hours of the technicians and more important: what working schedule they have at that day (please note that working schedule can change and have a start and end date) and what details (eg. job position) they had.

Thank you.

 

(I thought i could add documents but i cannot, so i put here the tables)

TechnicianDetails

TechnicianEnd DateStart DateOrganizationCostAreaJobPositionTechnician name
Tech1   9999-12-312023-01-01Organization1costarea1JobPosition3Tech1   
Tech2   9999-12-312023-01-15Organization1costarea2JobPosition1Tech2   
Tech2   2023-01-142022-12-04Organization3costarea3JobPosition2Tech2   
Tech39999-12-312023-01-01Organization2costarea2JobPosition3Tech3
Tech49999-12-312023-02-01Organization2costarea3JobPosition4Tech4

 

WorkingSchedule

TechnicianEnd DateStart DateWorkingSchedule  MoHrsWk.hrs.Hrs/DayWkDysAnnualHrs
Tech1   9999-12-312023-02-01Calendar116440851.968,00
Tech1   2023-01-312023-01-01Calendar2102,525551.230,00
Tech2   9999-12-312023-01-02Calendar2102,525551.230,00
Tech2   2023-01-012022-12-04Calendar398,424641.180,80
Tech39999-12-312023-02-15Calendar116440851.968,00
Tech32023-02-142023-01-01Calendar398,424641.180,80
Tech49999-12-312023-02-01Calendar116440851.968,00

 

RecordedHours

TechnicianRecording Date HoursHourTypeprojectRegistered on
Tech2   09/12/20223Workproject123/12/2022
Tech2   22/12/20221Travelproject423/12/2022
Tech1   09/01/20231Workproject320/01/2023
Tech1   10/01/20231Workproject420/01/2023
Tech1   11/01/20231Travelproject520/01/2023
Tech1   03/02/20238,5Workproject315/02/2023
Tech1   21/02/20233,5Workproject415/02/2023
Tech326/01/20232Lunchproject222/01/2023
Tech303/01/20238,5Workproject222/01/2023
Tech304/01/20238,5Workproject322/01/2023
Tech320/02/20238,5Workproject315/02/2023
Tech413/02/20235Workproject117/02/2023
Tech414/02/20235Workproject317/02/2023

When thinking of how to model the data you've shared, I would identify your distinct dimensions, pull them out, and construct the applicable bridge tables needed to define their interrletionships. Doing so would most likely result in a constellation model (star schema with multiple facts). 

 

Taking your original data tables, I constructed the below model (Dates is marked as a date table, all top tables are dimensions, bottom tables are facts):

 

MarkLaf_1-1745911031426.png

 

Which is a compoiste of the below three star schemas:

 

MarkLaf_2-1745911056470.png

MarkLaf_3-1745911086666.png

MarkLaf_4-1745911108358.png

 

With the above model, something like the below is relatively easy:

 

MarkLaf_5-1745911829983.png

 

Where the only DAX we have to write is for the measure:

 

Tech Hours = CALCULATE( SUM( TechHours[Hours] ), TechOrgDates, TechCalDates )

 

If you have any many-to many relationships (e.g., a tech could have two active calendars or be in two positions at the same time), then you should probably stick to a model like this.

 

If, though, for any given tech and date, you will only have one associated calendar and one associated org/position, then you can simplify the model by moving the foreign keys of your dimensions directly onto your main fact (TechHours). You can then directly relate all your dimensions to the one fact, like so:

 

MarkLaf_7-1745914164346.png

 

 

With that set up, then you would no even need to write any DAX for the visual example I used before, the implicit sum on TechHours[Hours] works:

 

MarkLaf_6-1745914130489.png

 

Follow up, to show more details of how exactly I transformed your original tables into the model(s) I shared. I did all the transformation/construction in Power Query. It would be possible to do all this in DAX, too, but then you'll have duplicated data loaded into your model.

 

MarkLaf_1-1745911031426.png

 

Here is all the M for the seven tables above.

 

Calendars

 

let
    Source = WorkingSchedule,
    SelectCols = Table.SelectColumns(
        Source, {"WorkingSchedule", "  MoHrs", "Wk.hrs.", "Hrs/Day", "WkDys", "AnnualHrs"}
    ),
    Distinct = Table.Distinct(SelectCols, {"WorkingSchedule"}),
    AddId = Table.AddIndexColumn(Distinct, "ID", 1, 1, Int64.Type),
    MoveIdFirst = Table.ReorderColumns(
        AddId, {"ID", "WorkingSchedule", "  MoHrs", "Wk.hrs.", "Hrs/Day", "WkDys", "AnnualHrs"}
    )
in
    MoveIdFirst

 

MarkLaf_8-1745915697111.png

 

Dates

 

let
    Source = RecordedHours[Recording Date],
    MinDate = List.Min(Source),
    MaxDate = List.Max(Source),
    Dates = List.Dates(
        Date.StartOfYear(MinDate),
        Duration.Days(Date.EndOfYear(MaxDate) - Date.StartOfYear(MinDate)) + 1,
        #duration(1, 0, 0, 0)
    ),
    ToTable = Table.FromColumns(
        {Dates}, 
        Type.AddTableKey(type table [Date = date], {"Date"}, true)
    ),
    AddYear = Table.AddColumn(ToTable, "Year", each Date.Year([Date]), Int64.Type),
    AddQuarter = Table.AddColumn(AddYear, "Quarter", each Date.QuarterOfYear([Date]), Int64.Type),
    AddMonthNo = Table.AddColumn(AddQuarter, "MonthNo", each Date.Month([Date]), Int64.Type),
    AddMonth = Table.AddColumn(AddMonthNo, "Month", each Date.MonthName([Date]), type text),
    AddYearMonthNo = Table.AddColumn(
        AddMonth, 
        "YearMonthNo", 
        each [Year] * 100 + [MonthNo], 
        Int64.Type
    ),
    AddYearMonth = Table.AddColumn(
        AddYearMonthNo, 
        "YearMonth", 
        each Text.From([Year]) & "-" & Text.Start([Month], 3), 
        type text
    )
in
    AddYearMonth

 

MarkLaf_9-1745915756047.png

 

Technicians

 

let
    Source = TechnicianDetails,
    SelectTechCols = Table.SelectColumns(Source,{"Technician", "Technician name"}),
    DistinctTech = Table.Distinct(SelectTechCols, {"Technician"}),
    AddId = Table.AddIndexColumn(DistinctTech, "ID", 1, 1, Int64.Type),
    MoveIdFirst = Table.ReorderColumns(AddId,{"ID", "Technician", "Technician name"})
in
    MoveIdFirst

 

MarkLaf_10-1745915792405.png

 

OrgPositions

 

let
    Source = TechnicianDetails,
    SelectOrgCols = Table.SelectColumns(Source,{"Organization", "JobPosition", "CostArea"}),
    Distinct = Table.Distinct(SelectOrgCols),
    AddId = Table.AddIndexColumn(Distinct, "ID", 1, 1, Int64.Type),
    MoveIdFirst = Table.ReorderColumns(AddId,{"ID", "Organization", "JobPosition", "CostArea"})
in
    MoveIdFirst

 

MarkLaf_11-1745915830117.png

 

TechCalDates

 

let
    Source = WorkingSchedule,
    MergeTechs = Table.NestedJoin(
        Source, {"Technician"}, 
        Technicians, {"Technician"}, 
        "Technicians", JoinKind.Inner
    ),
    MergeCals = Table.NestedJoin(
        MergeTechs, {"WorkingSchedule"}, 
        Calendars, {"WorkingSchedule"}, 
        "Calendars", JoinKind.Inner
    ),
    MaxDate = List.Max(Dates[Date]),
    AddDates = Table.AddColumn(
        MergeCals,
        "Dates",
        each List.Dates(
            [Start Date], 
            Duration.Days(List.Min({MaxDate, [End Date]}) - [Start Date]) + 1, 
            #duration(1, 0, 0, 0)
        ),
        type {date}
    ),
    SelectCols = Table.SelectColumns(AddDates, {"Technicians", "Calendars", "Dates"}),
    ExpandTechID = Table.ExpandTableColumn(SelectCols, "Technicians", {"ID"}, {"TechID"}),
    ExpandCalID = Table.ExpandTableColumn(ExpandTechID, "Calendars", {"ID"}, {"CalID"}),
    ExpandDates = Table.ExpandListColumn(ExpandCalID, "Dates")
in
    ExpandDates

 

MarkLaf_12-1745915872293.png

 

TechHours

 

let
    Source = RecordedHours,
    MergeTechs = Table.NestedJoin(
        Source, {"Technician"}, 
        Technicians, {"Technician"}, 
        "Technicians", JoinKind.Inner
    ),
    SelectCols = Table.SelectColumns(
        MergeTechs, 
        {"Technicians", "Recording Date", "Hours", "HourType", "project", "Registered on"}
    ),
    ExpandTechID = Table.ExpandTableColumn(SelectCols, "Technicians", {"ID"}, {"TechID"})
in
    ExpandTechID

 

MarkLaf_13-1745915901236.png

 

TechOrgDates

 

let
    Source = TechnicianDetails,
    MergeTechs = Table.NestedJoin(
        Source, {"Technician"}, 
        Technicians, {"Technician"}, 
        "Technicians", JoinKind.Inner
        ),
    MergeOrgPos = Table.NestedJoin(
        MergeTechs,
        {"Organization", "JobPosition", "CostArea"},
        OrgPositions,
        {"Organization", "JobPosition", "CostArea"},
        "OrgPositions",
        JoinKind.Inner
    ),
    MaxDate = List.Max(Dates[Date]),
    AddDates = Table.AddColumn(
        MergeOrgPos,
        "Dates",
        each List.Dates(
            [Start Date], 
            Duration.Days(List.Min({MaxDate, [End Date]}) - [Start Date]) + 1, 
            #duration(1, 0, 0, 0)
        ),
        type {date}
    ),
    SelectCols = Table.SelectColumns(AddDates, {"Technicians", "OrgPositions", "Dates"}),
    ExpandTechID = Table.ExpandTableColumn(SelectCols, "Technicians", {"ID"}, {"TechID"}),
    ExpandOrgPosID = Table.ExpandTableColumn(ExpandTechID, "OrgPositions", {"ID"}, {"OrgPosID"}),
    ExpandDates = Table.ExpandListColumn(ExpandOrgPosID, "Dates")
in
    ExpandDates

 

MarkLaf_14-1745915932878.png

 

If your business rules allow for the simplified model I described (no need to support M:M), then you can disable the load on the two bridge tables, TechCalDates & TechOrgDates, and use the below in TechHours to move the foreign keys over. (Note there are probably more efficient ways to get the FKs here without first building out the bridge tables):

 

let
    Source = RecordedHours,
    MergeTechs = Table.NestedJoin(
        Source, {"Technician"}, 
        Technicians, {"Technician"}, 
        "Technicians", JoinKind.Inner
    ),
    SelectCols = Table.SelectColumns(
        MergeTechs, 
        {"Technicians", "Recording Date", "Hours", "HourType", "project", "Registered on"}
    ),
    ExpandTechID = Table.ExpandTableColumn(SelectCols, "Technicians", {"ID"}, {"TechID"}),
    MergeCals = Table.NestedJoin(
        ExpandTechID, {"TechID", "Recording Date"}, 
        TechCalDates, {"TechID", "Dates"}, 
        "TechCalDates", JoinKind.Inner
    ),
    ExpandCalID = Table.ExpandTableColumn(MergeCals, "TechCalDates", {"CalID"}, {"CalID"}),
    MergeOrgs = Table.NestedJoin(
        ExpandCalID, {"TechID", "Recording Date"}, 
        TechOrgDates, {"TechID", "Dates"}, 
        "TechOrgDates", JoinKind.Inner
    ),
    ExpandOrgID = Table.ExpandTableColumn(MergeOrgs, "TechOrgDates", {"OrgPosID"}, {"OrgPosID"})
in
    ExpandOrgID

 

MarkLaf_0-1745916026783.png

Your WorkingSchedule table is inconclusive.  You need to specify which days of the week , and what the business hours are.  Same for the RecordedHours - needs a start and end time. Otherwise you don't know when they worked outside of the agreed days/hours.

Hi @lbendlin 

that's the way the information is coming from the source system. The assumption is that the recording is done in working days within business hours. For the report we don't care.

for me the main problem is how I can do the model to know the workingschedule valid for the day the hours were recorded. Thank you!

I cannot assist you with that in a meaningful way.I hope someone else can help you further.

Helpful resources

Announcements
July PBI25 Carousel

Power BI Monthly Update - July 2025

Check out the July 2025 Power BI update to learn about new features.

August 2025 community update carousel

Fabric Community Update - August 2025

Find out what's new and trending in the Fabric community.

Top Solution Authors
Top Kudoed Authors