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

A new Data Days event is coming soon! This time we’re going bigger than ever. Fabric, Power BI, SQL, AI and more. Don't miss out.

Reply
NicoRey
Frequent Visitor

Grouping with range

Hello,

 

I have a table with validaty range (FROM / TO) for the first column PN.

Below is an example.

I want to group in PowerQuery based on Column PN showing continuous validity ranges.

PN FROM    TO
A   22011    23011
A   23101    23371

A   23201    23471
B   21011    21101
B   21011    23011
B   22031    22301

 

Wanted result:

PN FROM   TO
A    22011   23011
A    23101   23471
B    21011   22301

 

I do not know if this possible to achieve.

Br

Nico

2 ACCEPTED SOLUTIONS

Hi @NicoRey,

 

The solution assumes and requires your data to be sorted, like the sample dataset. When that is not the case, it has to be incorporated because it works through your table, comparing values row by row in the order they appear.

 

let
    Source = YourTable,
    Order =  Table.Buffer( Table.Sort(Source,{{"PN", Order.Ascending}})),
    Rows = Table.ToRows( Order),
    Result = Table.FromRows( List.Accumulate(
        List.Skip(Rows, 1),
        {Rows{0}},
        (state, current) => 
            let
                prevRow = List.Last(state),
                updateState =
                    if (prevRow{0} = current{0}) and (current{1} <= prevRow{2}) then
                        List.RemoveLastN(state, 1) & {{prevRow{0}, prevRow{1}, current{2}}}
                    else
                        state & {current}
            in
                updateState
    ), Table.ColumnNames(Source))
in
    Result

 

I hope this is helpful

View solution in original post

dufoq3
Super User
Super User

Hi @NicoRey, different approach:

 

Result

dufoq3_0-1719397349702.png

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTIyMjA0BNHGIDpWBypqbGgAETU2RxY1goqaQEWdQDxDqAmGID0YonBznSC2GYNFQcJKsbEA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [PN = _t, FROM = _t, TO = _t]),
    ChangedType = Table.TransformColumnTypes(Source,{{"FROM", Int64.Type}, {"TO", Int64.Type}}),

    fn_FromTo = 
        (myTable as table)=>
        let
            // _Detail = GroupedRows{[PN="A"]}[All],
            _Detail = myTable,
            SelectedColumnsBuffer = Table.Buffer(Table.SelectColumns(_Detail,{"FROM", "TO"})),
            Generate = List.Generate(
                ()=> [ x = 0, from = SelectedColumnsBuffer{x}[FROM], to = SelectedColumnsBuffer{x}[TO], y = from, z = to, w = 1 ],
                each [x] < Table.RowCount(SelectedColumnsBuffer),
                each [ x = [x]+1,
                    from = SelectedColumnsBuffer{x}[FROM], 
                    to = SelectedColumnsBuffer{x}[TO],
                    y = if from <= [to] then [from] else from,
                    z = to,
                    w = if from <= [to] then 1 else 0 ]
        ),
            ToTableInner = Table.FromRecords(Generate),
            FilteredRowsInner = Table.SelectRows(ToTableInner, each ([w] = 1)),
            RemovedOtherColumnsInner = Table.SelectColumns(FilteredRowsInner,{"y", "z"}),
            GroupedRowsInner = Table.Group(RemovedOtherColumnsInner, {"y"}, {{"All", each _, Int64.Type}, {"FROM", each List.First([y]), Int64.Type}, {"TO", each List.Last([z]), Int64.Type}}),
            RemovedOtherColumnsInner2 = [ a = Table.RemoveColumns(_Detail, {"FROM", "TO"}),
            b = Table.SelectColumns(GroupedRowsInner,{"FROM", "TO"}),
            c = Table.FromColumns(Table.ToColumns(a) & Table.ToColumns(b), Value.Type(a & b) )
        ][c],
            FilteredRowsInner2 = Table.SelectRows(RemovedOtherColumnsInner2, each ([FROM] <> null))
        in
            FilteredRowsInner2,

    GroupedRows = Table.Group(ChangedType, {"PN"}, {{"All", fn_FromTo, Int64.Type}}),
    CombinedAll = Table.Combine(GroupedRows[All])
in 
    CombinedAll

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

4 REPLIES 4
dufoq3
Super User
Super User

Hi @NicoRey, different approach:

 

Result

dufoq3_0-1719397349702.png

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTIyMjA0BNHGIDpWBypqbGgAETU2RxY1goqaQEWdQDxDqAmGID0YonBznSC2GYNFQcJKsbEA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [PN = _t, FROM = _t, TO = _t]),
    ChangedType = Table.TransformColumnTypes(Source,{{"FROM", Int64.Type}, {"TO", Int64.Type}}),

    fn_FromTo = 
        (myTable as table)=>
        let
            // _Detail = GroupedRows{[PN="A"]}[All],
            _Detail = myTable,
            SelectedColumnsBuffer = Table.Buffer(Table.SelectColumns(_Detail,{"FROM", "TO"})),
            Generate = List.Generate(
                ()=> [ x = 0, from = SelectedColumnsBuffer{x}[FROM], to = SelectedColumnsBuffer{x}[TO], y = from, z = to, w = 1 ],
                each [x] < Table.RowCount(SelectedColumnsBuffer),
                each [ x = [x]+1,
                    from = SelectedColumnsBuffer{x}[FROM], 
                    to = SelectedColumnsBuffer{x}[TO],
                    y = if from <= [to] then [from] else from,
                    z = to,
                    w = if from <= [to] then 1 else 0 ]
        ),
            ToTableInner = Table.FromRecords(Generate),
            FilteredRowsInner = Table.SelectRows(ToTableInner, each ([w] = 1)),
            RemovedOtherColumnsInner = Table.SelectColumns(FilteredRowsInner,{"y", "z"}),
            GroupedRowsInner = Table.Group(RemovedOtherColumnsInner, {"y"}, {{"All", each _, Int64.Type}, {"FROM", each List.First([y]), Int64.Type}, {"TO", each List.Last([z]), Int64.Type}}),
            RemovedOtherColumnsInner2 = [ a = Table.RemoveColumns(_Detail, {"FROM", "TO"}),
            b = Table.SelectColumns(GroupedRowsInner,{"FROM", "TO"}),
            c = Table.FromColumns(Table.ToColumns(a) & Table.ToColumns(b), Value.Type(a & b) )
        ][c],
            FilteredRowsInner2 = Table.SelectRows(RemovedOtherColumnsInner2, each ([FROM] <> null))
        in
            FilteredRowsInner2,

    GroupedRows = Table.Group(ChangedType, {"PN"}, {{"All", fn_FromTo, Int64.Type}}),
    CombinedAll = Table.Combine(GroupedRows[All])
in 
    CombinedAll

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

m_dekorte
Resident Rockstar
Resident Rockstar

Hi @NicoRey 

 

Give this a go:

let
    Source = YourTable,
    Rows = Table.ToRows(Source),
    Result = Table.FromRows( List.Accumulate(
        List.Skip(Rows, 1),
        {Rows{0}},
        (state, current) => 
            let
                prevRow = List.Last(state),
                updateState =
                    if (prevRow{0} = current{0}) and (current{1} <= prevRow{2}) then
                        List.RemoveLastN(state, 1) & {{prevRow{0}, prevRow{1}, current{2}}}
                    else
                        state & {current}
            in
                updateState
    ), Table.ColumnNames(Source))
in
    Result

produces this result
m_dekorte_0-1718900473493.png

I hope this is helpful

Hi,

 

Thx for the reply.

I cannot say I understand the coding but copied it to try out.

Added an additional row for PN "A" with range from 23111 to 23461 with following result.

NicoRey_0-1719326477327.png

I my wanted solution this row doesn't show in the result as it "fits"  in the range of row 2 from 23101 to 23471.

 

Any ideas?

Hi @NicoRey,

 

The solution assumes and requires your data to be sorted, like the sample dataset. When that is not the case, it has to be incorporated because it works through your table, comparing values row by row in the order they appear.

 

let
    Source = YourTable,
    Order =  Table.Buffer( Table.Sort(Source,{{"PN", Order.Ascending}})),
    Rows = Table.ToRows( Order),
    Result = Table.FromRows( List.Accumulate(
        List.Skip(Rows, 1),
        {Rows{0}},
        (state, current) => 
            let
                prevRow = List.Last(state),
                updateState =
                    if (prevRow{0} = current{0}) and (current{1} <= prevRow{2}) then
                        List.RemoveLastN(state, 1) & {{prevRow{0}, prevRow{1}, current{2}}}
                    else
                        state & {current}
            in
                updateState
    ), Table.ColumnNames(Source))
in
    Result

 

I hope this is helpful

Helpful resources

Announcements
May Power BI Update Carousel

Power BI Monthly Update - May 2026

Check out the May 2026 Power BI update to learn about new features.

Fabric SQL PBI Data Days

Data Days 2026 coming soon!

Sign up to receive a private message when registration opens and key events begin.

New to Fabric survey Carousel

New to Fabric Survey

If you have recently started exploring Fabric, we'd love to hear how it's going. Your feedback can help with product improvements.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.