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

Enhance your career with this limited time 50% discount on Fabric and Power BI exams. Ends August 31st. Request your voucher.

Reply
MalAttari
Frequent Visitor

Changing consecutive dates to from dates

Hello 
I have following table 

PersonDateAssignment
Jack01-JanSupport
Jack02-JanSupport
Jack03-JanSupport
Jack04-JanAnalysis
Jack05-JanAnalysis
Jack08-JanAnalysis
Jack12-JanSupport


Can I tranform it to 

PersonFromToAssignment
Jack 01-Jan03-JanSupport
Jack 04-Jan05-JanAnalysis
Jack 08-Jan08-JanAnalysis
Jack 12-Jan12-JanSupport


I can do this in DAX struggling to do it in Power Query. Have tried various ways like getting previous / next dates and merging but not getting the result


4 ACCEPTED SOLUTIONS
DataNinja777
Super User
Super User

Hi @MalAttari ,

 

To achieve the desired transformation in Power Query, start by loading your table into Power Query and sorting it by the Person and Date columns in ascending order. After sorting, you need to identify consecutive rows with the same Assignment while ensuring that dates are sequential.

First, create an Index column to assist in identifying groups of consecutive assignments. To do this, go to the Add Column tab and select Index Column (From 0). Next, add a Custom Column to calculate a GroupID that identifies each consecutive block of the same assignment. You can do this using the following steps.

Go to Add Column > Custom Column and use the formula below:

 

 

let
    // Load your table
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

    // Sort the table by Person and Date
    SortedTable = Table.Sort(Source, {{"Person", Order.Ascending}, {"Date", Order.Ascending}}),

    // Buffer the table to improve performance and prevent referencing issues
    BufferedTable = Table.Buffer(SortedTable),

    // Add an Index column to help track row positions
    IndexedTable = Table.AddIndexColumn(BufferedTable, "Index", 0, 1, Int64.Type),

    // Add a GroupID column to identify consecutive assignments
    GroupedTable = Table.AddColumn(
        IndexedTable,
        "GroupID",
        each if [Index] = 0 then 0
        else if [Assignment] = BufferedTable{[Index]-1}[Assignment] 
             and [Person] = BufferedTable{[Index]-1}[Person] 
             and Date.AddDays(BufferedTable{[Index]-1}[Date], 1) = [Date] 
        then BufferedTable{[Index]-1}[GroupID]
        else BufferedTable{[Index]-1}[GroupID] + 1
    ),

    // Group by Person and GroupID, and calculate From and To dates
    GroupedResult = Table.Group(
        GroupedTable,
        {"Person", "GroupID"},
        {
            {"From", each List.Min([Date]), type date},
            {"To", each List.Max([Date]), type date},
            {"Assignment", each List.First([Assignment]), type text}
        }
    ),

    // Remove the GroupID column
    FinalTable = Table.RemoveColumns(GroupedResult, {"GroupID"})
in
    FinalTable

 

 

 

Best regards,

View solution in original post

slorin
Super User
Super User

Hi @MalAttari 

 

let
Source = Your_Source,
Index = Table.AddIndexColumn(Your_Source, "Index", 0, 1, Int64.Type),
Group = Table.Group(
Index,
{"Person", "Assignment", "Date", "Index"},
{{"From", each List.Min([Date]), type nullable date}, {"To", each List.Max([Date]), type nullable date}},
GroupKind.Local,
(x,y) => Number.From((y[Index]-x[Index]) <> Number.From(Duration.Days(y[Date]-x[Date]))
or y[Assignment] <> x[Assignment])),
Columns = Table.SelectColumns(Group,{"Person", "From", "To", "Assignment"})
in
Columns

Stéphane

View solution in original post

@speedramps 

You have to adapt this code

let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8kpMzlbSUTIw1AciIwMjUyAnuLSgIL+oRClWByFvREDemIC8CZK8Y15iTmVxZjGKAlNCCiwIKDDE6sRYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Person = _t, Date = _t, Assignment = _t]),
TypeDate = Table.TransformColumnTypes(Source, {{"Date", type date}}, "fr-FR"),
Index = Table.AddIndexColumn(TypeDate, "Index", 0, 1, Int64.Type),
Group = Table.Group(Index, {"Person", "Assignment", "Date", "Index"}, {{"From", each List.Min([Date]), type nullable date}, {"To", each List.Max([Date]), type nullable date}}, GroupKind.Local, (x,y) => Number.From((y[Index]-x[Index])<>Number.From(Duration.Days(y[Date]-x[Date])) or y[Assignment]<>x[Assignment])),
Columns = Table.SelectColumns(Group,{"Person", "From", "To", "Assignment"})
in
Columns

 Stéphane

View solution in original post

dufoq3
Super User
Super User

Hi @MalAttari, another solution:

 

Output

dufoq3_0-1736709391116.png

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8kpMzlbSUTIw1PVKzAMygksLCvKLSpRidRByRnjkjPHImUDlHPMScyqLM4tRJE3xSVrgkTTEcE4sAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Person = _t, Date = _t, Assignment = _t]),
    AddedIndex = Table.AddIndexColumn(Source, "Index", 0, 1, Int64.Type),
    GroupedRows = Table.Group(AddedIndex, {"Person", "Date", "Assignment", "Index"}, {{"T", each let a = Table.First(_), b = [Person = a[Person], From = a[Date], To = Table.Last(_)[Date], Assignment = a[Assignment]] in b, type table}}, 0,
        (x,y)=> Byte.From( y[Person] <> x[Person] or y[Assignment] <> x[Assignment] or Duration.TotalDays(Date.From(y[Date]) - Date.From(x[Date]))  > (y[Index] - x[Index]) ) ),
    CombinedT = Table.FromRecords(GroupedRows[T])
in
    CombinedT

Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

View solution in original post

9 REPLIES 9
dufoq3
Super User
Super User

Hi @MalAttari, another solution:

 

Output

dufoq3_0-1736709391116.png

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8kpMzlbSUTIw1PVKzAMygksLCvKLSpRidRByRnjkjPHImUDlHPMScyqLM4tRJE3xSVrgkTTEcE4sAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Person = _t, Date = _t, Assignment = _t]),
    AddedIndex = Table.AddIndexColumn(Source, "Index", 0, 1, Int64.Type),
    GroupedRows = Table.Group(AddedIndex, {"Person", "Date", "Assignment", "Index"}, {{"T", each let a = Table.First(_), b = [Person = a[Person], From = a[Date], To = Table.Last(_)[Date], Assignment = a[Assignment]] in b, type table}}, 0,
        (x,y)=> Byte.From( y[Person] <> x[Person] or y[Assignment] <> x[Assignment] or Duration.TotalDays(Date.From(y[Date]) - Date.From(x[Date]))  > (y[Index] - x[Index]) ) ),
    CombinedT = Table.FromRecords(GroupedRows[T])
in
    CombinedT

Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

Thanks @dufoq3, Works too. Going to see if there is a performace advantage of any. Have a few million rows. 

You're welcome.


Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

slorin
Super User
Super User

Hi @MalAttari 

 

let
Source = Your_Source,
Index = Table.AddIndexColumn(Your_Source, "Index", 0, 1, Int64.Type),
Group = Table.Group(
Index,
{"Person", "Assignment", "Date", "Index"},
{{"From", each List.Min([Date]), type nullable date}, {"To", each List.Max([Date]), type nullable date}},
GroupKind.Local,
(x,y) => Number.From((y[Index]-x[Index]) <> Number.From(Duration.Days(y[Date]-x[Date]))
or y[Assignment] <> x[Assignment])),
Columns = Table.SelectColumns(Group,{"Person", "From", "To", "Assignment"})
in
Columns

Stéphane

Thanks Stéphane, Going to go through it today.

DataNinja777
Super User
Super User

Hi @MalAttari ,

 

To achieve the desired transformation in Power Query, start by loading your table into Power Query and sorting it by the Person and Date columns in ascending order. After sorting, you need to identify consecutive rows with the same Assignment while ensuring that dates are sequential.

First, create an Index column to assist in identifying groups of consecutive assignments. To do this, go to the Add Column tab and select Index Column (From 0). Next, add a Custom Column to calculate a GroupID that identifies each consecutive block of the same assignment. You can do this using the following steps.

Go to Add Column > Custom Column and use the formula below:

 

 

let
    // Load your table
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

    // Sort the table by Person and Date
    SortedTable = Table.Sort(Source, {{"Person", Order.Ascending}, {"Date", Order.Ascending}}),

    // Buffer the table to improve performance and prevent referencing issues
    BufferedTable = Table.Buffer(SortedTable),

    // Add an Index column to help track row positions
    IndexedTable = Table.AddIndexColumn(BufferedTable, "Index", 0, 1, Int64.Type),

    // Add a GroupID column to identify consecutive assignments
    GroupedTable = Table.AddColumn(
        IndexedTable,
        "GroupID",
        each if [Index] = 0 then 0
        else if [Assignment] = BufferedTable{[Index]-1}[Assignment] 
             and [Person] = BufferedTable{[Index]-1}[Person] 
             and Date.AddDays(BufferedTable{[Index]-1}[Date], 1) = [Date] 
        then BufferedTable{[Index]-1}[GroupID]
        else BufferedTable{[Index]-1}[GroupID] + 1
    ),

    // Group by Person and GroupID, and calculate From and To dates
    GroupedResult = Table.Group(
        GroupedTable,
        {"Person", "GroupID"},
        {
            {"From", each List.Min([Date]), type date},
            {"To", each List.Max([Date]), type date},
            {"Assignment", each List.First([Assignment]), type text}
        }
    ),

    // Remove the GroupID column
    FinalTable = Table.RemoveColumns(GroupedResult, {"GroupID"})
in
    FinalTable

 

 

 

Best regards,

Thanks DataNinja777 going to go through it today

@slorin @DataNinja777 

When I try to copy and paste the M code it is not transposing.

Please can you save and share your PBIX solution with view access on OneDrive or Dropbox

You can download and use this PBIX, edit it and then save it with view access on you Onedrive or drop box. Then post the link in the chat.
Click here 

 

Thank you. I look forward to it.

@speedramps 

You have to adapt this code

let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8kpMzlbSUTIw1AciIwMjUyAnuLSgIL+oRClWByFvREDemIC8CZK8Y15iTmVxZjGKAlNCCiwIKDDE6sRYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Person = _t, Date = _t, Assignment = _t]),
TypeDate = Table.TransformColumnTypes(Source, {{"Date", type date}}, "fr-FR"),
Index = Table.AddIndexColumn(TypeDate, "Index", 0, 1, Int64.Type),
Group = Table.Group(Index, {"Person", "Assignment", "Date", "Index"}, {{"From", each List.Min([Date]), type nullable date}, {"To", each List.Max([Date]), type nullable date}}, GroupKind.Local, (x,y) => Number.From((y[Index]-x[Index])<>Number.From(Duration.Days(y[Date]-x[Date])) or y[Assignment]<>x[Assignment])),
Columns = Table.SelectColumns(Group,{"Person", "From", "To", "Assignment"})
in
Columns

 Stéphane

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.

Join our Fabric User Panel

Join our Fabric User Panel

This is your chance to engage directly with the engineering team behind Fabric and Power BI. Share your experiences and shape the future.

June 2025 community update carousel

Fabric Community Update - June 2025

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

Top Solution Authors