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

Earn a 50% discount on the DP-600 certification exam by completing the Fabric 30 Days to Learn It challenge.

Reply
wilson_smyth
Post Patron
Post Patron

Unpivoting multiple column groups

Hi.

I have a flat file where each row contains multiple column groups of data.
I need to get a row per group. I though unpivot functionality was the way to accomplish this but i have not been successful so far.

Below are examples of the source data and the final format required. Would appreciate any advice about how to tackle this.

 

IDDateDescAmountSplitAmount1_DescSplitAmount1SplitAmount2_DescSplitAmount2Reserve1_DescReserve1Amount
101/01/2020Donation1000fund A550Fund B400Reserved for contingency50
206/06/2021Donation400Fund J200  Additional Costs200

 

 

How i need it to look is as follows:

IDDateAmountSplitAmountDesc
101/01/20201000550Fund A
101/01/20201000400Fund B
101/01/2020100050Reserved for Contingency
206/06/2021400200Fund J
206/06/2021400200Additional Costs
1 ACCEPTED SOLUTION
AlexisOlson
Super User
Super User

Here's how I'd do it with pivoting and unpivoting:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VY2xCsMwDER/RWgORDZJ97SlQ8esxkOInWIoMsRuoX9fyc1SkOCedNw5hwY7JNPLWLIkcM281JRZpCHSy/biAJOIcVS8KZ5FDO07xxL3dwyw5R3WzDXxI/L6UT+h7xxarTj1MlJh/it+GS3yLsI2hGOnEJL6lidccqnlMHj/BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, Date = _t, Desc = _t, Amount = _t, SplitAmount1_Desc = _t, SplitAmount1 = _t, SplitAmount2_Desc = _t, SplitAmount2 = _t, Reserve1_Desc = _t, Reserve1Amount = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date", type date}, {"Desc", type text}, {"Amount", Int64.Type}, {"SplitAmount1_Desc", type text}, {"SplitAmount1", Int64.Type}, {"SplitAmount2_Desc", type text}, {"SplitAmount2", Int64.Type}, {"Reserve1_Desc", type text}, {"Reserve1Amount", Int64.Type}}),
    #"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Reserve1_Desc", "Reserve1Amount_Desc"}}),
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Renamed Columns", {"Amount", "Desc", "Date", "ID"}, "Attribute", "Value"),
    #"Split Column by Delimiter" = Table.SplitColumn(#"Unpivoted Other Columns", "Attribute", Splitter.SplitTextByEachDelimiter({"_"}, QuoteStyle.Csv, false), {"Label", "PivotColumn"}),
    #"Replaced Value" = Table.ReplaceValue(#"Split Column by Delimiter",null,"SplitAmount",Replacer.ReplaceValue,{"PivotColumn"}),
    #"Removed Columns" = Table.RemoveColumns(#"Replaced Value",{"Desc"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[PivotColumn]), "PivotColumn", "Value"),
    #"Reordered Columns" = Table.ReorderColumns(#"Pivoted Column",{"ID", "Date", "Amount", "SplitAmount", "Label", "Desc"})
in
    #"Reordered Columns"

 

You can also do it without pivoting and unpivoting like this:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VY2xCsMwDER/RWgORDZJ97SlQ8esxkOInWIoMsRuoX9fyc1SkOCedNw5hwY7JNPLWLIkcM281JRZpCHSy/biAJOIcVS8KZ5FDO07xxL3dwyw5R3WzDXxI/L6UT+h7xxarTj1MlJh/it+GS3yLsI2hGOnEJL6lidccqnlMHj/BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, Date = _t, Desc = _t, Amount = _t, SplitAmount1_Desc = _t, SplitAmount1 = _t, SplitAmount2_Desc = _t, SplitAmount2 = _t, Reserve1_Desc = _t, Reserve1Amount = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date", type date}, {"Desc", type text}, {"Amount", Int64.Type}, {"SplitAmount1_Desc", type text}, {"SplitAmount1", Int64.Type}, {"SplitAmount2_Desc", type text}, {"SplitAmount2", Int64.Type}, {"Reserve1_Desc", type text}, {"Reserve1Amount", Int64.Type}}),
    #"Removed Other Columns" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "SplitAmount1_Desc", "SplitAmount1"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Other Columns",{{"SplitAmount1_Desc", "Desc"}, {"SplitAmount1", "SplitAmount"}}),
    #"Removed Other Columns1" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "SplitAmount2_Desc", "SplitAmount2"}),
    #"Renamed Columns1" = Table.RenameColumns(#"Removed Other Columns1",{{"SplitAmount2_Desc", "Desc"}, {"SplitAmount2", "SplitAmount"}}),
    #"Removed Other Columns2" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "Reserve1_Desc", "Reserve1Amount"}),
    #"Renamed Columns2" = Table.RenameColumns(#"Removed Other Columns2",{{"Reserve1_Desc", "Desc"}, {"Reserve1Amount", "SplitAmount"}}),
    #"Appended Query" = Table.Combine({#"Renamed Columns", #"Renamed Columns1", #"Renamed Columns2"}),
    #"Sorted Rows" = Table.Sort(#"Appended Query",{{"ID", Order.Ascending}}),
    #"Filtered Rows" = Table.SelectRows(#"Sorted Rows", each ([SplitAmount] <> null))
in
    #"Filtered Rows"

 

View solution in original post

2 REPLIES 2
AlexisOlson
Super User
Super User

Here's how I'd do it with pivoting and unpivoting:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VY2xCsMwDER/RWgORDZJ97SlQ8esxkOInWIoMsRuoX9fyc1SkOCedNw5hwY7JNPLWLIkcM281JRZpCHSy/biAJOIcVS8KZ5FDO07xxL3dwyw5R3WzDXxI/L6UT+h7xxarTj1MlJh/it+GS3yLsI2hGOnEJL6lidccqnlMHj/BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, Date = _t, Desc = _t, Amount = _t, SplitAmount1_Desc = _t, SplitAmount1 = _t, SplitAmount2_Desc = _t, SplitAmount2 = _t, Reserve1_Desc = _t, Reserve1Amount = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date", type date}, {"Desc", type text}, {"Amount", Int64.Type}, {"SplitAmount1_Desc", type text}, {"SplitAmount1", Int64.Type}, {"SplitAmount2_Desc", type text}, {"SplitAmount2", Int64.Type}, {"Reserve1_Desc", type text}, {"Reserve1Amount", Int64.Type}}),
    #"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Reserve1_Desc", "Reserve1Amount_Desc"}}),
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Renamed Columns", {"Amount", "Desc", "Date", "ID"}, "Attribute", "Value"),
    #"Split Column by Delimiter" = Table.SplitColumn(#"Unpivoted Other Columns", "Attribute", Splitter.SplitTextByEachDelimiter({"_"}, QuoteStyle.Csv, false), {"Label", "PivotColumn"}),
    #"Replaced Value" = Table.ReplaceValue(#"Split Column by Delimiter",null,"SplitAmount",Replacer.ReplaceValue,{"PivotColumn"}),
    #"Removed Columns" = Table.RemoveColumns(#"Replaced Value",{"Desc"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns", List.Distinct(#"Removed Columns"[PivotColumn]), "PivotColumn", "Value"),
    #"Reordered Columns" = Table.ReorderColumns(#"Pivoted Column",{"ID", "Date", "Amount", "SplitAmount", "Label", "Desc"})
in
    #"Reordered Columns"

 

You can also do it without pivoting and unpivoting like this:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VY2xCsMwDER/RWgORDZJ97SlQ8esxkOInWIoMsRuoX9fyc1SkOCedNw5hwY7JNPLWLIkcM281JRZpCHSy/biAJOIcVS8KZ5FDO07xxL3dwyw5R3WzDXxI/L6UT+h7xxarTj1MlJh/it+GS3yLsI2hGOnEJL6lidccqnlMHj/BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, Date = _t, Desc = _t, Amount = _t, SplitAmount1_Desc = _t, SplitAmount1 = _t, SplitAmount2_Desc = _t, SplitAmount2 = _t, Reserve1_Desc = _t, Reserve1Amount = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date", type date}, {"Desc", type text}, {"Amount", Int64.Type}, {"SplitAmount1_Desc", type text}, {"SplitAmount1", Int64.Type}, {"SplitAmount2_Desc", type text}, {"SplitAmount2", Int64.Type}, {"Reserve1_Desc", type text}, {"Reserve1Amount", Int64.Type}}),
    #"Removed Other Columns" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "SplitAmount1_Desc", "SplitAmount1"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Other Columns",{{"SplitAmount1_Desc", "Desc"}, {"SplitAmount1", "SplitAmount"}}),
    #"Removed Other Columns1" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "SplitAmount2_Desc", "SplitAmount2"}),
    #"Renamed Columns1" = Table.RenameColumns(#"Removed Other Columns1",{{"SplitAmount2_Desc", "Desc"}, {"SplitAmount2", "SplitAmount"}}),
    #"Removed Other Columns2" = Table.SelectColumns(#"Changed Type",{"ID", "Date", "Amount", "Reserve1_Desc", "Reserve1Amount"}),
    #"Renamed Columns2" = Table.RenameColumns(#"Removed Other Columns2",{{"Reserve1_Desc", "Desc"}, {"Reserve1Amount", "SplitAmount"}}),
    #"Appended Query" = Table.Combine({#"Renamed Columns", #"Renamed Columns1", #"Renamed Columns2"}),
    #"Sorted Rows" = Table.Sort(#"Appended Query",{{"ID", Order.Ascending}}),
    #"Filtered Rows" = Table.SelectRows(#"Sorted Rows", each ([SplitAmount] <> null))
in
    #"Filtered Rows"

 

I like the non-pivoting version, but may be generalised it as below:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VY2xCsMwDER/RWgORDZJ97SlQ8esxkOInWIoMsRuoX9fyc1SkOCedNw5hwY7JNPLWLIkcM281JRZpCHSy/biAJOIcVS8KZ5FDO07xxL3dwyw5R3WzDXxI/L6UT+h7xxarTj1MlJh/it+GS3yLsI2hGOnEJL6lidccqnlMHj/BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, Date = _t, Desc = _t, Amount = _t, SplitAmount1_Desc = _t, SplitAmount1 = _t, SplitAmount2_Desc = _t, SplitAmount2 = _t, Reserve1_Desc = _t, Reserve1Amount = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date", type date}, {"Desc", type text}, {"Amount", Int64.Type}, {"SplitAmount1_Desc", type text}, {"SplitAmount1", Int64.Type}, {"SplitAmount2_Desc", type text}, {"SplitAmount2", Int64.Type}, {"Reserve1_Desc", type text}, {"Reserve1Amount", Int64.Type}}),
    
    Rules = {
                {"Desc",                "SplitAmount"},
                {"SplitAmount1_Desc",   "SplitAmount1"},
                {"SplitAmount2_Desc",   "SplitAmount2"},
                {"Reserve1_Desc",       "Reserve1Amount"}
            },
    Permanent = List.RemoveItems(Table.ColumnNames(#"Changed Type"), List.Combine(Rules)),
    
    f = (cols as list)=>
        let 
            #"Removed Other Columns" = Table.SelectColumns(#"Changed Type",Permanent & cols),
            #"Renamed Columns" = Table.RenameColumns(#"Removed Other Columns",List.Zip({cols} & {Rules{0}}))
        in #"Renamed Columns",
    
    Process = List.Accumulate(List.Skip(Rules), #table({},{}), (a,n)=> Table.Combine({a, f(n)})),
    #"Sorted Rows" = Table.Sort(Process,{{"ID", Order.Ascending}}),
    #"Filtered Rows" = Table.SelectRows(#"Sorted Rows", each ([SplitAmount] <> null))
in
    #"Filtered Rows"

Helpful resources

Announcements
LearnSurvey

Fabric certifications survey

Certification feedback opportunity for the community.

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

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

Top Solution Authors
Top Kudoed Authors