Forum Discussion
Unpivot multiple category columns into attributes and values
- 1 year ago
This can be done via List.Range and Table.SelectColumns.
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcssvylUwVNJRckktzkzPAzKc83NzU/NKwIKG+ob6RgZGptjkjYFsI30TiHysDpJRzvl5xSVFpcklmfnIGoyAbFN9Q2OQDhPcykzA5hoZQZTBDTbC5gZTsJFmMBMx5M2BbAt9CyxG4bDcDORpQ4SJOJRZANnmcK/ExgIA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, A.Type = _t, A.Comments = _t, A.Date = _t, B.Type = _t, B.Comments = _t, B.Date = _t]), Process = (tbl,col)=> let s = Table.SelectColumns(tbl,{"ID"} & col), newcol = List.Transform(col, each if Text.Length(_)>2 then Text.Range(_,2) else _), t = Table.RenameColumns(s,List.Zip({col,newcol})) in Table.AddColumn(t,"Category",each Text.Start(col{1},1)), Combined = Process(Source,List.Range(Table.ColumnNames(Source),1,3)) & Process(Source, List.Range(Table.ColumnNames(Source),4,3)), #"Reordered Columns" = Table.ReorderColumns(Combined,{"ID", "Category", "Type", "Comments", "Date"}) in #"Reordered Columns"How to use this code: Create a new Blank Query. Click on "Advanced Editor". Replace the code in the window with the code provided here. Click "Done". Once you examined the code, replace the entire Source step with your own source.
- 1 year ago
hello arpitprakash89
please check if this accomodate your need.
1. Merged type, comment, and date of A with any delimiter (i used colon). then put "A" as column name.
2. do exact same for "B"
3. unpivot A and B column
4. split the value column by colon delimiter since i used colon as delimiter when merging
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcssvylUwVNJRckktzkzPAzKc83NzU/NKwIKG+ob6RgZGptjkjYFsI30TiHysDpJRzvl5xSVFpcklmfnIGoyAbFN9Q2OQDhPcykzA5hoZQZTBDTbC5gZTsJFmMBMx5M2BbAt9CyxG4bDcDORpQ4SJOJRZANnmcK/ExgIA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, #"A.Type " = _t, A.Comments = _t, A.Date = _t, B.Type = _t, B.Comments = _t, B.Date = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", type text}, {"A.Type ", type text}, {"A.Comments", type text}, {"A.Date", type date}, {"B.Type", type text}, {"B.Comments", type text}, {"B.Date", type date}}),
#"Merged Columns" = Table.CombineColumns(Table.TransformColumnTypes(#"Changed Type", {{"A.Date", type text}}, "en-US"),{"A.Type ", "A.Comments", "A.Date"},Combiner.CombineTextByDelimiter(":", QuoteStyle.None),"A"),
#"Merged Columns1" = Table.CombineColumns(Table.TransformColumnTypes(#"Merged Columns", {{"B.Date", type text}}, "en-US"),{"B.Type", "B.Comments", "B.Date"},Combiner.CombineTextByDelimiter(":", QuoteStyle.None),"B"),
#"Unpivoted Columns" = Table.UnpivotOtherColumns(#"Merged Columns1", {"ID"}, "Attribute", "Value"),
#"Split Column by Delimiter" = Table.SplitColumn(#"Unpivoted Columns", "Value", Splitter.SplitTextByDelimiter(":", QuoteStyle.Csv), {"Value.1", "Value.2", "Value.3"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Value.1", type text}, {"Value.2", type text}, {"Value.3", type date}})
in
#"Changed Type1"Hope this will help.
Thank you.
This can be done via List.Range and Table.SelectColumns.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcssvylUwVNJRckktzkzPAzKc83NzU/NKwIKG+ob6RgZGptjkjYFsI30TiHysDpJRzvl5xSVFpcklmfnIGoyAbFN9Q2OQDhPcykzA5hoZQZTBDTbC5gZTsJFmMBMx5M2BbAt9CyxG4bDcDORpQ4SJOJRZANnmcK/ExgIA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, A.Type = _t, A.Comments = _t, A.Date = _t, B.Type = _t, B.Comments = _t, B.Date = _t]),
Process = (tbl,col)=>
let
s = Table.SelectColumns(tbl,{"ID"} & col),
newcol = List.Transform(col, each if Text.Length(_)>2 then Text.Range(_,2) else _),
t = Table.RenameColumns(s,List.Zip({col,newcol}))
in
Table.AddColumn(t,"Category",each Text.Start(col{1},1)),
Combined = Process(Source,List.Range(Table.ColumnNames(Source),1,3)) & Process(Source, List.Range(Table.ColumnNames(Source),4,3)),
#"Reordered Columns" = Table.ReorderColumns(Combined,{"ID", "Category", "Type", "Comments", "Date"})
in
#"Reordered Columns"
How to use this code: Create a new Blank Query. Click on "Advanced Editor". Replace the code in the window with the code provided here. Click "Done". Once you examined the code, replace the entire Source step with your own source.
Would it be possible to make your script a little more flexible? It works with the sample data I provided, however, my production data is a bit more complex.
Instead of the first character for Categories, I need to use the position of '.' as an identifier. This is because the Categories can be a longer string than just one character. Eg. "ProjectA.Comment"
Also, the columns are not always sequential. For Category A, it could be {Type, Comment, Date} but Category B may be {Comment, Type, Date}.
Sorry, should have clarified in the original question 😞
- lbendlin1 year ago
Super User
Please provide sample data that fully covers your issue.
Please show the expected outcome based on the sample data you provided.- arpitprakash891 year agoFrequent Visitor
lbendlin , here's a more accurate dataset.
Things to consider -
The no. of Deliverables and Type can change in the columns Deliverable.Type;
I need to account for empty/null fields.
Again, appreciate the assistance!!Form Model.Assigned To Model.Status Model.Completion Model.Comments Model.Due Date Other.Comments Other.Assigned To Other.Due Date Other.Status Other.Completion Configure Plans and Specs.Comments Configure Plans and Specs.Assigned To Configure Plans and Specs.Due Date Configure Plans and Specs.Status Configure Plans and Specs.Completion Form-01 Bryce Tex In Progress 50 Comments 1 12/20/2024 Comments 4 Form-02 Boone Harmony Complete 100 Comments 2 Denton Lorraine 2/19/2025 Not Started Comments 5 Brandi Tate 1/15/205 In Progress 70 Form-03 Brandi Tate Complete 100 Comments 3 1/3/2025 Comments 6 Finn Cheyenne 11/18/2024 Complete 100 Form Deliverable Assigned To Status Completion Comments Due Date Form-01 Model Bryce Tex In Progress 50 Comments 1 12/20/2024 Form-01 Other Comments 4 Form-01 Configure Plans and Specs Form-02 Model Boone Harmony Complete 100 Form-02 Other Denton Lorraine Not Started 1/15/2025 Form-02 Configure Plans and Specs Brandi Tate In Progress 70 Form-03 Model Brandi Tate Complete 100 1/3/2025 Form-03 Other Form-03 Configure Plans and Specs Finn Cheyenne Complete 100 11/18/2024 - lbendlin1 year ago
Super User
That's actually much simpler to implement.
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("hVBNi8IwEP0rQ89Kk7jx42pFdkGWBb1JD0EHLdgZSXPY/nsn1ZaIuwiZMC95M+/N7PfZmn09VjobZUvfHhB2+Cv5F8GP55PHphFklVwF1zVSaCBytcmNkmM+0p8I4G2Uo17VRFVmQvh0vmZq782uFwwYRdSTrkm6rOSFCTbsvasokk2uF9GQlfybA2yD8wGPD/7QxHaDOjpWsHOdCuhcW6m0L2PPVOJ18lL4v9PI1fmkt/PXGgbuVMC6IoLijC1SN4sWS/Nku6lMWd4A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Form = _t, #"Model.Assigned To" = _t, Model.Status = _t, Model.Completion = _t, Model.Comments = _t, #"Model.Due Date" = _t, Other.Comments = _t, #"Other.Assigned To" = _t, #"Other.Due Date" = _t, Other.Status = _t, Other.Completion = _t, #"Configure Plans and Specs.Comments" = _t, #"Configure Plans and Specs.Assigned To" = _t, #"Configure Plans and Specs.Due Date" = _t, #"Configure Plans and Specs.Status" = _t, #"Configure Plans and Specs.Completion" = _t]), #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Form"}, "Attribute", "Value"), #"Filtered Rows" = Table.SelectRows(#"Unpivoted Other Columns", each ([Value] <> " ")), #"Split Column by Delimiter" = Table.SplitColumn(#"Filtered Rows", "Attribute", Splitter.SplitTextByEachDelimiter({"."}, QuoteStyle.Csv, false), {"Deliverable", "Attribute.2"}), #"Pivoted Column" = Table.Pivot(#"Split Column by Delimiter", List.Distinct(#"Split Column by Delimiter"[Attribute.2]), "Attribute.2", "Value") in #"Pivoted Column"