Forum Discussion

Anonymous's avatar
Anonymous
Not applicable
3 years ago
Solved

Unpivot or unstack columns dynamically

I get data from outkook emails which are stacked in power query where each day's emails have tables with different headers.

Currently data is like below where first 4 rows represent table 1 from day 1 and last 4 rows is from 2nd table from day 2 and so on.  

 

Day 1Value AValue BValue C
A123
B456
C789
Day 2Value AValue CValue D
A101112
B141516
C171819

 

I want this table to unpivot link below:

 

DayCategoryTypeValue
Day 1AValue A1
Day 1AValue B2
Day 1AValue C3
Day 1BValue A4
Day 1BValue B5
Day 1BValue C6
Day 1CValue A7
Day 1CValue B8
Day 1CValue C9
Day 2AValue A10
Day 2AValue C11
Day 2AValue D12
Day 2BValue A14
Day 2BValue C15
Day 2BValue D16
Day 2CValue A17
Day 2CValue C18
Day 2CValue D19

 

Thanks in adcance for help.

Regards.

  • Try this:

    It works on your sample

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("bY0rDoAwEESv0qxGMOUvoT0DpqmowGER3J6diq1BvGYy3cxLSWJ5HaSTs9zP5XZLh6UguUvCH955ZagNL0ZlUubaBE2Lsipbbbjuf9aDpdjWez50wJsANIAKNAcoAS1QTf4A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Column1 = _t, Column2 = _t, Column3 = _t, Column4 = _t]),
        #"Changed Type" = Table.TransformColumnTypes(Source,{
            {"Column1", type text}, {"Column2", type text}, {"Column3", type text}, {"Column4", type text}}),
    
    //Add column to group by dates
        #"Added Custom" = Table.AddColumn(#"Changed Type", "Day", each if Text.StartsWith([Column1],"Day") then [Column1] else null, type nullable text),
        #"Filled Down" = Table.FillDown(#"Added Custom",{"Day"}),
    
    //Unpivot each subgroup
        #"Grouped Rows" = Table.Group(#"Filled Down", {"Day"}, {
            {"UNPivot", (t)=>
                let 
                    #"Promote Headers" = Table.PromoteHeaders(t),
                    #"Removed Columns" = Table.RemoveColumns(#"Promote Headers", List.Last(Table.ColumnNames(#"Promote Headers"))),
                    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{List.First(Table.ColumnNames(#"Removed Columns")),"Category"}}),
                    #"Unpivot" = Table.UnpivotOtherColumns(#"Renamed Columns",{"Category"},"Type","Value"),
                    #"Value to Number" = Table.TransformColumns(#"Unpivot",{"Value", each Number.From(_)})
                in 
                    #"Value to Number",
                type table[Category=text, Type=text, Value=number]}
            }),
        
        #"Expanded UNPivot" = Table.ExpandTableColumn(#"Grouped Rows", "UNPivot", {"Category", "Type", "Value"})
     
    in
        #"Expanded UNPivot"

     

     

     

3 Replies

  • Try this:

    It works on your sample

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("bY0rDoAwEESv0qxGMOUvoT0DpqmowGER3J6diq1BvGYy3cxLSWJ5HaSTs9zP5XZLh6UguUvCH955ZagNL0ZlUubaBE2Lsipbbbjuf9aDpdjWez50wJsANIAKNAcoAS1QTf4A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Column1 = _t, Column2 = _t, Column3 = _t, Column4 = _t]),
        #"Changed Type" = Table.TransformColumnTypes(Source,{
            {"Column1", type text}, {"Column2", type text}, {"Column3", type text}, {"Column4", type text}}),
    
    //Add column to group by dates
        #"Added Custom" = Table.AddColumn(#"Changed Type", "Day", each if Text.StartsWith([Column1],"Day") then [Column1] else null, type nullable text),
        #"Filled Down" = Table.FillDown(#"Added Custom",{"Day"}),
    
    //Unpivot each subgroup
        #"Grouped Rows" = Table.Group(#"Filled Down", {"Day"}, {
            {"UNPivot", (t)=>
                let 
                    #"Promote Headers" = Table.PromoteHeaders(t),
                    #"Removed Columns" = Table.RemoveColumns(#"Promote Headers", List.Last(Table.ColumnNames(#"Promote Headers"))),
                    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{List.First(Table.ColumnNames(#"Removed Columns")),"Category"}}),
                    #"Unpivot" = Table.UnpivotOtherColumns(#"Renamed Columns",{"Category"},"Type","Value"),
                    #"Value to Number" = Table.TransformColumns(#"Unpivot",{"Value", each Number.From(_)})
                in 
                    #"Value to Number",
                type table[Category=text, Type=text, Value=number]}
            }),
        
        #"Expanded UNPivot" = Table.ExpandTableColumn(#"Grouped Rows", "UNPivot", {"Category", "Type", "Value"})
     
    in
        #"Expanded UNPivot"

     

     

     

  • Anonymous's avatar
    Anonymous
    Not applicable

    Thanks ronrsnfld . This worked. I need to learn this part.

     

     #"Grouped Rows" = Table.Group(#"Filled Down", {"Day"}, {
            {"UNPivot", (t)=>
                let 
                    #"Promote Headers" = Table.PromoteHeaders(t),
                    #"Removed Columns" = Table.RemoveColumns(#"Promote Headers", List.Last(Table.ColumnNames(#"Promote Headers"))),
                    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{List.First(Table.ColumnNames(#"Removed Columns")),"Category"}}),
                    #"Unpivot" = Table.UnpivotOtherColumns(#"Renamed Columns",{"Category"},"Type","Value"),
                    #"Value to Number" = Table.TransformColumns(#"Unpivot",{"Value", each Number.From(_)})
                in 
                    #"Value to Number",
                type table[Category=text, Type=text, Value=number]}
            }),

     Regards.

    • ronrsnfld's avatar
      ronrsnfld
      Super User

      If you set up a data sample with just a single day, so you don't have to put those steps within a Table.Group aggregaion, those are the steps (after the #"Filled Down") that would unpivot the single day. It may be easier to follow that way.