Find everything you need to get certified on Fabric—skills challenges, live sessions, exam prep, role guidance, and more. Get started
Hello
Is there an easy way to use Power Query to pivot data with a Unique ID spread over multiple rows, into a spreadsheet with one row per ID?
eg I have 22 milestones below, each milestone has 7 values columns.
How do I pivot the milestone column 7 times to create 154 columns in each unique ID row?
eg I need it to display like this, as this data needs to be merged with an existing legacy excel report
Do I need to duplicate the milestone column 7 times, then pivot each milestone duplicate against each value column?
If so is there an easy way to rename each new column to "Milestone 0 Active", "Milestone 1 Active" etc without having to manually rename 154 columns?
Thanks very much
Solved! Go to Solution.
Assuming all of the ID's have all of the Milestone's listed in proper order, You can:
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"
Please provide your data sample as text which can be copy/pasted. Much simpler than trying to work from a screenshot.
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:
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"
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
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})
...
Your solution is amazing, it works wonderful and is easy to follow. Thank you for sharing.
Thanks very much that worked!
Check out the September 2024 Power BI update to learn about new features.
Learn from experts, get hands-on experience, and win awesome prizes.
User | Count |
---|---|
41 | |
23 | |
21 | |
20 | |
13 |
User | Count |
---|---|
128 | |
58 | |
48 | |
28 | |
20 |