Because the way a form is set up, every time a user fills out the form, different quarter information is stored in a single row. For data analysis purposes and simplicity, I would like to "transpose and merge" the columns with the same information. In this case all the columns containing **quarter **information and **value **information.
I have the following table:
Deal | 1ST Quarter | 2ND Quarter | 3RD Quarter | Value 1ST Quarter | Value 2ND Quarter | Value 3RD Quarter |
---|---|---|---|---|---|---|
A | Q2 | Q3 | Null | $100 | $200 | Null |
B | Q1 | Q2 | Q3 | $50 | $30 | $40 |
I want to transpose the Quarter columns and their respective values and output the following:
Deal | Quarter | Value |
---|---|---|
A | Q2 | $100 |
A | Q3 | $100 |
A | Null | Null |
B | Q1 | $50 |
B | Q2 | $30 |
B | Q3 | $40 |
I have tried transposing the columns but end up making a mess and multiple rows.
Another approach, possibly more efficient, is to
Attribute
column to show only Quarter
and Value
The problem with the latter step, using the usual Pivot operation in PQ, is that it will result in an error. However, this custom function avoids that issue.
Paste the code below into a blank query in the Advanced Editor and rename it fnPivotNoAggregation
Custom Function
//credit: Cam Wallace https://www.dingbatdata.com/2018/03/08/non-aggregate-pivot-with-multiple-rows-in-powerquery/
//Rename: fnPivotNoAggregation
(Source as table,
ColToPivot as text,
ColForValues as text)=>
let
PivotColNames = List.Buffer(List.Distinct(Table.Column(Source,ColToPivot))),
#"Pivoted Column" = Table.Pivot(Source, PivotColNames, ColToPivot, ColForValues, each _),
TableFromRecordOfLists = (rec as record, fieldnames as list) =>
let
PartialRecord = Record.SelectFields(rec,fieldnames),
RecordToList = Record.ToList(PartialRecord),
Table = Table.FromColumns(RecordToList,fieldnames)
in
Table,
#"Added Custom" = Table.AddColumn(#"Pivoted Column", "Values", each TableFromRecordOfLists(_,PivotColNames)),
#"Removed Other Columns" = Table.RemoveColumns(#"Added Custom",PivotColNames),
#"Expanded Values" = Table.ExpandTableColumn(#"Removed Other Columns", "Values", PivotColNames)
in
#"Expanded Values"
Then use the following for the Main code:
Main Code
let
//Change next line to reflect actual Table name
Source = Excel.CurrentWorkbook(){[Name="Table12"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Deal", type text}, {"1ST Quarter", type text}, {"2ND Quarter", type text},
{"3RD Quarter", type text}, {"Value 1ST Quarter", Int64.Type},
{"Value 2ND Quarter", Int64.Type}, {"Value 3RD Quarter", type any}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Deal"}, "Attribute", "Values"),
Normalize = Table.TransformColumns(#"Unpivoted Other Columns",
{"Attribute", each let first = Text.BeforeDelimiter(_," ") in if first <> "Value" then "Quarter" else "Value"}),
Pivot = fnPivotNoAggregation(Normalize,"Attribute","Values")
in
Pivot
Note: It is possible to do this without a custom function, but the execution time would be a bit longer.
You can certainly test both and ascertain which is more efficient with your actual data
let
//Change next line to reflect actual data source
Source = Excel.CurrentWorkbook(){[Name="Table12"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Deal", type text}, {"1ST Quarter", type text}, {"2ND Quarter", type text},
{"3RD Quarter", type text}, {"Value 1ST Quarter", Int64.Type}, {"Value 2ND Quarter", Int64.Type}, {"Value 3RD Quarter", type any}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Deal"}, "Attribute", "Value"),
Normalize = Table.TransformColumns(#"Unpivoted Other Columns",
{"Attribute", each let first = Text.BeforeDelimiter(_," ") in if first <> "Value" then "Quarter" else "Value"}),
#"Grouped Rows" = Table.Group(Normalize, {"Deal"}, {
{"QV", (t)=>
Table.FromColumns(
{Table.SelectRows(t, each [Attribute]= "Quarter")[Value],
Table.SelectRows(t, each [Attribute]="Value")[Value]}, {"Quarter","Value"}
), type table[Quarter=text, Value=Currency.Type]}}),
#"Expanded QV" = Table.ExpandTableColumn(#"Grouped Rows", "QV", {"Quarter", "Value"}, {"Quarter", "Value"})
in
#"Expanded QV"