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

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now! Learn more

Reply
wallace158
Frequent Visitor

Remodeling Data in Power Query, data not normalized

Hello all,

 

I am working with our companies financial team and they have our budget organized with a sales account and total sales for each month with each month having its own column. It Looks like this

CustomerJan SalesFeb SalesMar SalesApril SalesMay SalesJune SalesJuly Sales
Cust 15212132516132131214123211258
Cust 25611312131531611517496515261
Cust 32156151665165115616516513218656161

 

I am trying to normalize the data to look like this:

CustomerMonthSales
Cust 11

521

Cust 12

2132

Cust 21

561

Cust 22

131

 

Currently, I have figured out how to do this but would love to hear if there is a better way. My Current Technique:

  • Merge all the columns into 1 column, called 'merged col', with a delimiter ";".
  • Create a custom column with the following M code: 

 

= let
  templist = Text.split([merged_col],";")
  final = "1," & templist{0},"2," & templist{1},"3," & templist{2},"4," & templist{3},"5," & templist{4},"6," & templist{5},"7," & templist{6},"8," & templist{7},"9," & templist{8},"10," & templist{9},"11," & templist{10},"12," & templist{11}
in
final​

 

  • This creates a column that looks like this for Cust 1: 1,521;2,2132;3,5161;4,3213;5,1214;6,1232;7,11258 etc, it basically creates a list out of the merged column, and then adds a month id to each value within the ";" delimiter, using "," as a secondary delimiter.
  • I can then "split columns" on ";" and split to rows.
  • Then split columns on "," and split to columns.
  • Then I delete the old Jan,Feb,Mar Sales Columns
  • That gives me the desired result.

This seems to be kinda weird, so I would love to see if anyone has a slick way to accomplish this. Thanks guys!

1 ACCEPTED SOLUTION
BA_Pete
Super User
Super User

Hi @wallace158 ,

 

I would do it this way. It should be a bit more dynamic than your current solution which appears to rely on the data being in a specific order to allocate the month numbers correctly. It will also be much clearer and easier to understand for future devs of your report:

 

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("PY67EcAgDENXybmmkcEOqTMGxxRJ9o8/HI11wnoyY9D9Pe8BKiTsk1HZDdRdNWsCRguJHcDSaZbFRjzSqKsB4mxWQHCatEslHNvrZmvkRTPnoiaSXODb21e65ilvmD8=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Customer = _t, #"Jan Sales" = _t, #"Feb Sales" = _t, #"Mar Sales" = _t, #"April Sales" = _t, #"May Sales" = _t, #"June Sales" = _t, #"July Sales" = _t]),
    unpivOthCols = Table.UnpivotOtherColumns(Source, {"Customer"}, "Attribute", "Sales"),
    splitAttribBySpace = Table.SplitColumn(unpivOthCols, "Attribute", Splitter.SplitTextByDelimiter(" ", QuoteStyle.Csv), {"Attribute.1", "Attribute.2"}),
    extractFirstThreeChars = Table.TransformColumns(splitAttribBySpace, {{"Attribute.1", each Text.Start(_, 3), type text}}),
    addMonth = Table.AddColumn(extractFirstThreeChars, "month", each
if [Attribute.1] = "Jan" then 1
else if [Attribute.1] = "Feb" then 2
else if [Attribute.1] = "Mar" then 3
else if [Attribute.1] = "Apr" then 4
else if [Attribute.1] = "May" then 5
else if [Attribute.1] = "Jun" then 6
else if [Attribute.1] = "Jul" then 7
else if [Attribute.1] = "Aug" then 8
else if [Attribute.1] = "Sep" then 9
else if [Attribute.1] = "Oct" then 10
else if [Attribute.1] = "Nov" then 11
else if [Attribute.1] = "Dec" then 12
else null),
    remOthCols = Table.SelectColumns(addMonth,{"Customer", "month", "Sales"})
in
    remOthCols

 

 

Summary:

1) Unpivot columns other than [customer], changing the "Value" name to "Sales" in the formula bar

2) Split new [attribute] column by space ( " " ) delimiter

3) Extract first three characters of current month name (to simplify next step)

4) Add [month] column using conditional evaluation

5) Remove columns other than those required

 

My output:

BA_Pete_0-1645434838562.png

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




View solution in original post

10 REPLIES 10
MBreden
Helper I
Helper I

Another dynamic solution with the date of the current year:

 

 

let
    Quelle = Excel.CurrentWorkbook(){[Name="wallace158"]}[Content],
    #"Entpivotierte andere Spalten" = Table.UnpivotOtherColumns(Quelle, {"Customer"}, "Date", "Sales"),
    #"Ersetzter Wert" = Table.ReplaceValue(#"Entpivotierte andere Spalten", "Sales",Number.ToText( Date.Year(DateTime.LocalNow())),Replacer.ReplaceText,{"Date"}),
    #"Geänderter Typ" = Table.TransformColumnTypes(#"Ersetzter Wert",{{"Date", type date}, {"Customer", type text}, {"Sales", Int64.Type}})
in
    #"Geänderter Typ"

 

 

 Melanie

Daryl-Lynch-Bzy
Resident Rockstar
Resident Rockstar

Hi @wallace158  - I would recommend using "Date" instead of "Month Number",  it would provide to be more flexible in the future.

let
#"Year" = 2022,
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("PY67EcAgDENXybmmkcEOqTMGxxRJ9o8/HI11wnoyY9D9Pe8BKiTsk1HZDdRdNWsCRguJHcDSaZbFRjzSqKsB4mxWQHCatEslHNvrZmvkRTPnoiaSXODb21e65ilvmD8=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Customer = _t, #"Jan Sales" = _t, #"Feb Sales" = _t, #"Mar Sales" = _t, #"April Sales" = _t, #"May Sales" = _t, #"June Sales" = _t, #"July Sales" = _t]),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Customer"}, "Month", "Sales"),
#"Extracted First Characters" = Table.TransformColumns(#"Unpivoted Other Columns", {{"Month", each Text.Start(_, 3), type text}}),
#"Added Custom" = Table.AddColumn(#"Extracted First Characters", "Correct Month", each Date.FromText( Text.From(#"Year") & "-" & [Month] & "-01"), type date)
in
#"Added Custom"

 

DarylLynchBzy_0-1645436714878.png

 

Hi @Daryl-Lynch-Bzy ,

 

I totally agree that using a proper date would be the ideal scenario.

The issue I had was that OP didn't imply there was a date field in their data, so you actually lose flexibility by now having a hardcoded year in the query.

 

@wallace158 Do you have a year datapoint anywhere in your source that could be dynamically applied to this to create proper dates?

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




@BA_Pete, yes I actually do. Because the original data source has all the months in different columns, there is a column with "22". So once I finish my above method and add the month number in a column, I create a new field with "#date(2000+[year],[month],1). Then I link this new date field to the calendar dimension. I should have had this in my original question.

 

Cool. Looks like you've got everything you need then 🙂👍

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




BA_Pete
Super User
Super User

Hi @wallace158 ,

 

I would do it this way. It should be a bit more dynamic than your current solution which appears to rely on the data being in a specific order to allocate the month numbers correctly. It will also be much clearer and easier to understand for future devs of your report:

 

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("PY67EcAgDENXybmmkcEOqTMGxxRJ9o8/HI11wnoyY9D9Pe8BKiTsk1HZDdRdNWsCRguJHcDSaZbFRjzSqKsB4mxWQHCatEslHNvrZmvkRTPnoiaSXODb21e65ilvmD8=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Customer = _t, #"Jan Sales" = _t, #"Feb Sales" = _t, #"Mar Sales" = _t, #"April Sales" = _t, #"May Sales" = _t, #"June Sales" = _t, #"July Sales" = _t]),
    unpivOthCols = Table.UnpivotOtherColumns(Source, {"Customer"}, "Attribute", "Sales"),
    splitAttribBySpace = Table.SplitColumn(unpivOthCols, "Attribute", Splitter.SplitTextByDelimiter(" ", QuoteStyle.Csv), {"Attribute.1", "Attribute.2"}),
    extractFirstThreeChars = Table.TransformColumns(splitAttribBySpace, {{"Attribute.1", each Text.Start(_, 3), type text}}),
    addMonth = Table.AddColumn(extractFirstThreeChars, "month", each
if [Attribute.1] = "Jan" then 1
else if [Attribute.1] = "Feb" then 2
else if [Attribute.1] = "Mar" then 3
else if [Attribute.1] = "Apr" then 4
else if [Attribute.1] = "May" then 5
else if [Attribute.1] = "Jun" then 6
else if [Attribute.1] = "Jul" then 7
else if [Attribute.1] = "Aug" then 8
else if [Attribute.1] = "Sep" then 9
else if [Attribute.1] = "Oct" then 10
else if [Attribute.1] = "Nov" then 11
else if [Attribute.1] = "Dec" then 12
else null),
    remOthCols = Table.SelectColumns(addMonth,{"Customer", "month", "Sales"})
in
    remOthCols

 

 

Summary:

1) Unpivot columns other than [customer], changing the "Value" name to "Sales" in the formula bar

2) Split new [attribute] column by space ( " " ) delimiter

3) Extract first three characters of current month name (to simplify next step)

4) Add [month] column using conditional evaluation

5) Remove columns other than those required

 

My output:

BA_Pete_0-1645434838562.png

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




Wow @BA_Pete, this looks really good! but I don't understand the first row in the source table, "json.document(binary.fromtext", I'm reading about it now but having trouble understanding why it should be in the first row?

Hi @wallace158 ,

 

I copied your example table into 'Enter Data' in Power Query. When you use this feature, it's built/stored as a JSON binary (in text format), so this is what you are seeing as the source. It makes it easier for you to copy the whole M code I provided and paste it into a new blank query using Avanced Editor in PQ. This gives you a working example in PQ for you to observe/test the effect of each of my steps.

On your own data, you would effectively start from my 'unpivOthCols' step.

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




👏👏👏thank you so much! I understand now. yes this works great and I was able to break down the steps into different table in a blank .pbi file so I could see it clearly. is there a good way to link the file in here for others?

Hi @wallace158 ,

 

I don't think there's any need to link your file here.

The beauty of the code I shared is that anybody can just copy and paste it into their own Power Query if they want to follow the steps.

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




Helpful resources

Announcements
Power BI DataViz World Championships

Power BI Dataviz World Championships

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now!

December 2025 Power BI Update Carousel

Power BI Monthly Update - December 2025

Check out the December 2025 Power BI Holiday Recap!

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.