Forum Discussion
How to pivot Multiple Columns
- 3 years ago
Assuming all of the ID's have all of the Milestone's listed in proper order, You can:
- Group by ID
- For each sub-table
- Select the ID and Milestone columns and UNPIVOT other columns
- Merge the Milestone and Attribute column => the new column headers
- Remove the original columns and more the new merged column to Column2
- Transpose the resultant table
- Remove the top row and make the next row the new headers
- Re-Expand the grouped table
In the code below, change line 2 to reflect your actual data source
let Source = Excel.CurrentWorkbook(){[Name="Table7"]}[Content], #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Milestone", type text}, {"Actual Completion Date", type date}, {"Actual Start Date", type date}, {"Active", type text}, {"Activity Status", type text}}), #"Grouped Rows" = Table.Group(#"Changed Type", {"ID"}, { {"Transpose", (t)=> let #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(t, {"ID", "Milestone"}, "Attribute", "Value"), #"Inserted Merged Column" = Table.AddColumn( #"Unpivoted Other Columns", "Merged", each Text.Combine({[Milestone], [Attribute]}, " - "), type text), #"Removed Columns" = Table.RemoveColumns(#"Inserted Merged Column",{"Milestone", "Attribute"}), #"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"ID", "Merged", "Value"}), #"Transposed Table" = Table.Transpose(#"Reordered Columns"), #"Removed Top Rows" = Table.Skip(#"Transposed Table",1), #"Promoted Headers" = Table.PromoteHeaders(#"Removed Top Rows", [PromoteAllScalars=true]) in #"Promoted Headers"}}), #"Column Names" = Table.ColumnNames(#"Grouped Rows"[Transpose]{0}), #"Data Types" = List.Transform(#"Column Names", each if Text.EndsWith(_, "Date") then {_, type date} else {_, type text}), #"Expanded Transpose" = Table.ExpandTableColumn(#"Grouped Rows", "Transpose", #"Column Names"), #"Set Data Types" = Table.TransformColumnTypes(#"Expanded Transpose", #"Data Types") in #"Set Data Types"
Here is some sample data
| ID | Milestone | Actual Completion Date | Actual Start Date | Active | Activity Status |
| 105610934 | Milestone 0 | 2023-02-22 | 2023-02-22 | No | Completed |
| 105610934 | Milestone 1 | No | Not Started | ||
| 105610934 | Milestone 1.1 | 2023-02-26 | No | Completed | |
| 105610934 | Milestone 1.2 | 2023-02-26 | Yes | In Progress | |
| 105610934 | Milestone 1.3 | No | Not Started | ||
| 105610934 | Milestone 1.4 | 2023-02-26 | Yes | In Progress | |
| 105610934 | Milestone 2 | No | Not Started | ||
| 105610934 | Milestone 2.1 | No | Not Started | ||
| 105610934 | Milestone 2.2 | No | Not Started | ||
| 105610934 | Milestone 2.3 | No | Not Started | ||
| 105610934 | Milestone 2.4 | No | Not Started | ||
| 105610934 | Milestone 2.5 | No | Not Started | ||
| 105610934 | Milestone 2.6 | No | Not Started | ||
| 105610934 | Milestone 3 | No | Not Started | ||
| 105610934 | Milestone 3.1 | No | Not Started | ||
| 105610934 | Milestone 3.2 | No | Not Started | ||
| 105610934 | Milestone 3.3 | No | Not Started | ||
| 105610934 | Milestone 3.4 | No | Not Started | ||
| 105610934 | Milestone 3.5 | No | Not Started | ||
| 105610934 | Milestone 3.6 | No | Not Started | ||
| 105610934 | Milestone 4 | No | Not Started | ||
| 105610934 | Milestone 4.1 | No | Not Started | ||
| 105728888 | Milestone 0 | 2023-02-23 | Yes | In Progress | |
| 105728888 | Milestone 1 | No | Not Started | ||
| 105728888 | Milestone 1.1 | No | Not Started | ||
| 105728888 | Milestone 1.2 | No | Not Started | ||
| 105728888 | Milestone 1.3 | No | Not Started | ||
| 105728888 | Milestone 1.4 | No | Not Started | ||
| 105728888 | Milestone 2 | No | Not Started | ||
| 105728888 | Milestone 2.1 | No | Not Started | ||
| 105728888 | Milestone 2.2 | No | Not Started | ||
| 105728888 | Milestone 2.3 | No | Not Started | ||
| 105728888 | Milestone 2.4 | No | Not Started | ||
| 105728888 | Milestone 2.5 | No | Not Started | ||
| 105728888 | Milestone 2.6 | No | Not Started | ||
| 105728888 | Milestone 3 | No | Not Started | ||
| 105728888 | Milestone 3.1 | No | Not Started | ||
| 105728888 | Milestone 3.2 | No | Not Started | ||
| 105728888 | Milestone 3.3 | No | Not Started | ||
| 105728888 | Milestone 3.4 | No | Not Started | ||
| 105728888 | Milestone 3.5 | No | Not Started | ||
| 105728888 | Milestone 3.6 | No | Not Started | ||
| 105728888 | Milestone 4 | No | Not Started | ||
| 105728888 | Milestone 4.1 | No | Not Started | ||
| 105744750 | Milestone 0 | 2023-02-23 | 2023-02-23 | No | Completed |
| 105744750 | Milestone 1 | No | Not Started | ||
| 105744750 | Milestone 1.1 | 2023-02-23 | No | Completed | |
| 105744750 | Milestone 1.2 | 2023-02-23 | 2023-02-23 | Yes | In Progress |
| 105744750 | Milestone 1.3 | No | Not Started | ||
| 105744750 | Milestone 1.4 | 2023-02-23 | 2023-02-23 | Yes | In Progress |
| 105744750 | Milestone 2 | No | Not Started | ||
| 105744750 | Milestone 2.1 | 2023-02-23 | Yes | In Progress | |
| 105744750 | Milestone 2.2 | No | Not Started | ||
| 105744750 | Milestone 2.3 | No | Not Started | ||
| 105744750 | Milestone 2.4 | No | Not Started | ||
| 105744750 | Milestone 2.5 | No | Not Started | ||
| 105744750 | Milestone 2.6 | No | Not Started | ||
| 105744750 | Milestone 3 | No | Not Started | ||
| 105744750 | Milestone 3.1 | No | Not Started | ||
| 105744750 | Milestone 3.2 | No | Not Started | ||
| 105744750 | Milestone 3.3 | No | Not Started | ||
| 105744750 | Milestone 3.4 | No | Not Started | ||
| 105744750 | Milestone 3.5 | No | Not Started | ||
| 105744750 | Milestone 3.6 | No | Not Started | ||
| 105744750 | Milestone 4 | No | Not Started | ||
| 105744750 | Milestone 4.1 | No | Not Started | ||
| 105744917 | Milestone 0 | 2023-02-23 | 2023-02-23 | No | Completed |
| 105744917 | Milestone 1 | No | Not Started | ||
| 105744917 | Milestone 1.1 | 2023-02-23 | No | Completed | |
| 105744917 | Milestone 1.2 | 2023-02-23 | 2023-02-23 | No | Completed |
| 105744917 | Milestone 1.3 | No | Not Started | ||
| 105744917 | Milestone 1.4 | 2023-02-23 | 2023-02-23 | No | Completed |
| 105744917 | Milestone 2 | No | Not Started | ||
| 105744917 | Milestone 2.1 | 2023-02-23 | Yes | In Progress | |
| 105744917 | Milestone 2.2 | No | Not Started | ||
| 105744917 | Milestone 2.3 | No | Not Started | ||
| 105744917 | Milestone 2.4 | No | Not Started | ||
| 105744917 | Milestone 2.5 | No | Not Started | ||
| 105744917 | Milestone 2.6 | No | Not Started | ||
| 105744917 | Milestone 3 | No | Not Started | ||
| 105744917 | Milestone 3.1 | No | Not Started | ||
| 105744917 | Milestone 3.2 | No | Not Started | ||
| 105744917 | Milestone 3.3 | No | Not Started | ||
| 105744917 | Milestone 3.4 | No | Not Started | ||
| 105744917 | Milestone 3.5 | No | Not Started | ||
| 105744917 | Milestone 3.6 | No | Not Started | ||
| 105744917 | Milestone 4 | No | Not Started | ||
| 105744917 | Milestone 4.1 | No | Not Started |
Assuming all of the ID's have all of the Milestone's listed in proper order, You can:
- Group by ID
- For each sub-table
- Select the ID and Milestone columns and UNPIVOT other columns
- Merge the Milestone and Attribute column => the new column headers
- Remove the original columns and more the new merged column to Column2
- Transpose the resultant table
- Remove the top row and make the next row the new headers
- Re-Expand the grouped table
In the code below, change line 2 to reflect your actual data source
let
Source = Excel.CurrentWorkbook(){[Name="Table7"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Milestone", type text}, {"Actual Completion Date", type date}, {"Actual Start Date", type date}, {"Active", type text}, {"Activity Status", type text}}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"ID"}, {
{"Transpose", (t)=>
let
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(t, {"ID", "Milestone"}, "Attribute", "Value"),
#"Inserted Merged Column" =
Table.AddColumn(
#"Unpivoted Other Columns", "Merged", each Text.Combine({[Milestone], [Attribute]}, " - "), type text),
#"Removed Columns" = Table.RemoveColumns(#"Inserted Merged Column",{"Milestone", "Attribute"}),
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"ID", "Merged", "Value"}),
#"Transposed Table" = Table.Transpose(#"Reordered Columns"),
#"Removed Top Rows" = Table.Skip(#"Transposed Table",1),
#"Promoted Headers" = Table.PromoteHeaders(#"Removed Top Rows", [PromoteAllScalars=true])
in #"Promoted Headers"}}),
#"Column Names" = Table.ColumnNames(#"Grouped Rows"[Transpose]{0}),
#"Data Types" = List.Transform(#"Column Names", each if Text.EndsWith(_, "Date") then {_, type date} else {_, type text}),
#"Expanded Transpose" = Table.ExpandTableColumn(#"Grouped Rows", "Transpose", #"Column Names"),
#"Set Data Types" = Table.TransformColumnTypes(#"Expanded Transpose", #"Data Types")
in
#"Set Data Types"
- dpwhitey13 years agoFrequent Visitor
Thanks very much that worked!
- HS-PA3 years agoRegular Visitor
Your solution is amazing, it works wonderful and is easy to follow. Thank you for sharing.
- joelengelhardt3 years agoNew Member
Thank you for sharing this! For my use for a Word mail merge, I added steps to dynamically use the largest Table to expand the Grouped Rows. This enables using this even if the Pivot value isn't present for each group. Basically, I
- Added a Row count aggregate column to the "Grouped Rows" action, alongside the Transpose column you created
- Added an Index column
- Calculated the Maximum count to determine which table had the MOST rows (that become columns later)
- Filtered the Table to show only Rows with a [Count] equal to the max
- Removed everything except for the first Row
- Drilled down to the Index value of this record
- Used THIS INDEX as the key for getting the Column Names
- (kept everything after the same)
These steps could certainly be consolidated and shortened to quickly return the Index of the table with ALL columns present.
Here's the code:
...
#"Grouped Rows" = Table.Group(#"Merged Columns", {"ID"}, {
{"Transpose", (t)=>
let
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(t, {"ID", "Milestone"}, "Attribute", "Value"),
#"Inserted Merged Column" =
Table.AddColumn(
#"Unpivoted Other Columns", "Merged", each Text.Combine({[Milestone], [Attribute]}, ""), type text),
#"Removed Columns" = Table.RemoveColumns(#"Inserted Merged Column",{"Milestone", "Attribute"}),
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"ID", "Merged", "Value"}),
#"Transposed Table" = Table.Transpose(#"Reordered Columns"),
#"Removed Top Rows" = Table.Skip(#"Transposed Table",1),
#"Promoted Headers" = Table.PromoteHeaders(#"Removed Top Rows", [PromoteAllScalars=true])
in #"Promoted Headers"},
{"Count", each Table.RowCount(_), Int64.Type}}),
#"Added Index" = Table.AddIndexColumn(#"Grouped Rows", "Index", 0, 1, Int64.Type),
#"Calculated Maximum" = List.Max(#"Added Index"[Count]),
#"Filtered Rows" = Table.SelectRows(#"Added Index", each ([Count] = #"Calculated Maximum")),
#"Kept First Rows" = Table.FirstN(#"Filtered Rows",1),
IndexOfMax = #"Kept First Rows"{[Count=#"Calculated Maximum"]}[Index],
#"Column Names" = Table.ColumnNames(#"Grouped Rows"[Transpose]{IndexOfMax})
...