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

July 7 - July 17 | Round 2 of the Power BI Dataviz World Championships. Don't miss your chance! Learn more

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
Community Champion
Community Champion

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
Community Champion
Community Champion

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
FabCon and SQLCon Barcelona 2026

FabCon & SQLCon – Barcelona 2026

Join us in Barcelona for FabCon and SQLCon, the Fabric, Power BI, SQL, and AI community event. Save €200 with code FABCMTY200.

60 days of Data Days Carousel

Data Days 2026

Join Fabric Data Days 2026: 60 days of free live/on-demand sessions, challenges, study groups, and certification opportunities.

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.