Macro to Stack row of headers x times then next header xtimes in Column

L VBA L

New Member
Joined
Oct 10, 2024
Messages
4
Office Version
  1. 2021
Platform
  1. Windows
I have some data with categories going across the top which I want to stack so the data set is repeated multiple times and only have 1 columns with results.
1728574848729.png


Turn it into this:
1728574895251.png



I managed to replicate the Food, Live Colour Categories but cant work out how to stack dog then catc then rabbit?


EDIT:
This data is all made up and may not make sense but its the principal i require.
 
Last edited by a moderator:

Excel Facts

Show numbers in thousands?
Use a custom number format of #,##0,K. Each comma after the final 0 will divide the displayed number by another thousand
With Power Query, Unpivot your data

Power Query:
let
    Source = Excel.CurrentWorkbook(){[Name="Table2"]}[Content],
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Food", "Live", "Colour"}, "Attribute", "Value"),
    #"Sorted Rows" = Table.Sort(#"Unpivoted Other Columns",{{"Attribute", Order.Ascending}}),
    #"Reordered Columns" = Table.ReorderColumns(#"Sorted Rows",{"Attribute", "Food", "Live", "Colour", "Value"})
in
    #"Reordered Columns"

Power Query is a free AddIn for Excel 2010 and 2013, and is built-in functionality from Excel 2016 onwards (where it is referred to as "Get & Transform Data").

It is a powerful yet simple way of getting, changing and using data from a broad variety of sources, creating steps which may be easily repeated and refreshed. I strongly recommend learning how to use Power Query - it's among the most powerful functionalities of Excel.

- Follow this link to learn how to install Power Query in Excel 2010 / 2013.

- Follow this link for an introduction to Power Query functionality.

- Follow this link for a video which demonstrates how to use Power Query code provided.
 
Upvote 0
Apologies this may work but the names of the headers change between sheets and can be between 20-60 different names. Is there a way I don't have to type in the header names?
 
Upvote 0
Here is some VBA code that seems to do what you want:
Rich (BB code):
Sub MyCopyData()

    Dim srcSht As Worksheet
    Dim dstSht As Worksheet
    Dim c1 As Long
    Dim c2 As Long
    Dim c3 As Long
    Dim c4 As Long
    Dim lr As Long
    Dim c As Long
    Dim nr As Long
    Dim nc As Long
    Dim hdr As String
    
    
'   Specify source sheet and destination sheet
    Set srcSht = Sheets("Sheet1")
    Set dstSht = Sheets("Sheet2")
    
'   Specify the starting and ending column for the descriptions
    c1 = 1  'first descriptive column in column A (1st column)
    c2 = 3  'last descriptive column in column C (3rd column)
    
    Application.ScreenUpdating = False

'   Populate title row on source sheet
    dstSht.Range("A1") = "Animal"
    srcSht.Range(srcSht.Cells(1, c1), srcSht.Cells(1, c2)).Copy dstSht.Range("B1")
    nc = dstSht.Cells(1, dstSht.Columns.Count).End(xlToLeft).Column + 1 'determine new column on destination sheet for totals
    dstSht.Cells(1, nc) = "Total"

'   Find last row with data on source sheet
    lr = srcSht.Cells(Rows.Count, c1).End(xlUp).Row
    
'   Calculate data columns to loop through
    c3 = c2 + 1
    c4 = srcSht.Cells(1, Columns.Count).End(xlToLeft).Column
    
'   Verify there are columns to data to go through
    If c3 > c4 Then
        MsgBox "Please fix data or VBA code", vbOKOnly, "There does not seem to be any data columns to go through!"
        Exit Sub
    End If
    
'   Loop through data columns
    For c = c3 To c4
'       Grab column header
        hdr = srcSht.Cells(1, c)
'       Determine next available row on Source sheet
        nr = dstSht.Cells(dstSht.Rows.Count, "A").End(xlUp).Row + 1
'       Populate the new data
        dstSht.Range(dstSht.Cells(nr, "A"), dstSht.Cells(nr + lr - 2, "A")) = hdr 'populate header value in first column
        srcSht.Range(srcSht.Cells(2, c1), srcSht.Cells(lr, c2)).Copy dstSht.Cells(nr, 2) 'copy over descriptive data to next columns
        srcSht.Range(srcSht.Cells(2, c), srcSht.Cells(lr, c)).Copy dstSht.Cells(nr, nc)   'copy over totals column
    Next c
    
    Application.ScreenUpdating = True
    
End Sub
I am assuming your first list starts in A1.
I tried to make it general enough that you should only have to edit the few items in red to suit your needs.

Here is the sample data from Sheet1:
1728651550635.png


and here is the output it produced on Sheet2:
1728651577227.png
 
Upvote 0
Solution
Here is some VBA code that seems to do what you want:
Rich (BB code):
Sub MyCopyData()

    Dim srcSht As Worksheet
    Dim dstSht As Worksheet
    Dim c1 As Long
    Dim c2 As Long
    Dim c3 As Long
    Dim c4 As Long
    Dim lr As Long
    Dim c As Long
    Dim nr As Long
    Dim nc As Long
    Dim hdr As String
   
   
'   Specify source sheet and destination sheet
    Set srcSht = Sheets("Sheet1")
    Set dstSht = Sheets("Sheet2")
   
'   Specify the starting and ending column for the descriptions
    c1 = 1  'first descriptive column in column A (1st column)
    c2 = 3  'last descriptive column in column C (3rd column)
   
    Application.ScreenUpdating = False

'   Populate title row on source sheet
    dstSht.Range("A1") = "Animal"
    srcSht.Range(srcSht.Cells(1, c1), srcSht.Cells(1, c2)).Copy dstSht.Range("B1")
    nc = dstSht.Cells(1, dstSht.Columns.Count).End(xlToLeft).Column + 1 'determine new column on destination sheet for totals
    dstSht.Cells(1, nc) = "Total"

'   Find last row with data on source sheet
    lr = srcSht.Cells(Rows.Count, c1).End(xlUp).Row
   
'   Calculate data columns to loop through
    c3 = c2 + 1
    c4 = srcSht.Cells(1, Columns.Count).End(xlToLeft).Column
   
'   Verify there are columns to data to go through
    If c3 > c4 Then
        MsgBox "Please fix data or VBA code", vbOKOnly, "There does not seem to be any data columns to go through!"
        Exit Sub
    End If
   
'   Loop through data columns
    For c = c3 To c4
'       Grab column header
        hdr = srcSht.Cells(1, c)
'       Determine next available row on Source sheet
        nr = dstSht.Cells(dstSht.Rows.Count, "A").End(xlUp).Row + 1
'       Populate the new data
        dstSht.Range(dstSht.Cells(nr, "A"), dstSht.Cells(nr + lr - 2, "A")) = hdr 'populate header value in first column
        srcSht.Range(srcSht.Cells(2, c1), srcSht.Cells(lr, c2)).Copy dstSht.Cells(nr, 2) 'copy over descriptive data to next columns
        srcSht.Range(srcSht.Cells(2, c), srcSht.Cells(lr, c)).Copy dstSht.Cells(nr, nc)   'copy over totals column
    Next c
   
    Application.ScreenUpdating = True
   
End Sub
I am assuming your first list starts in A1.
I tried to make it general enough that you should only have to edit the few items in red to suit your needs.

Here is the sample data from Sheet1:
View attachment 117983

and here is the output it produced on Sheet2:
View attachment 117984
This worked great. My data didn't start in A1 (actually C10) but I managed to update this and it worked spot on.

I did encounter an issue though as my data has between 3-40 columns for the Animals then a repeat of these columns to show a different cost which I dont want to pull through. In essence it created a duplicate set of rows for the second set of data.

I assume this is due to the VBA going to the last column to stop. If I added a cell that did a count of the number of columns I wanted it to do the above for could we work that into the formula?

Thanks again.
 
Upvote 0
This worked great. My data didn't start in A1 (actually C10) but I managed to update this and it worked spot on.

I did encounter an issue though as my data has between 3-40 columns for the Animals then a repeat of these columns to show a different cost which I dont want to pull through. In essence it created a duplicate set of rows for the second set of data.

I assume this is due to the VBA going to the last column to stop. If I added a cell that did a count of the number of columns I wanted it to do the above for could we work that into the formula?

Thanks again.
I don't understand what you are saying.
Can you show us an example data image to describe what you are trying to say?
 
Upvote 0
1732133630186.png


There are about 40 columns from E that could be used and sometimes are blank like the above. Then there are another 40 columns that is doing a calculation (like L-M above) but I dont need them for this exercise, I'm only interested in up to G so I could add a cell somewhere counting the columns I'm interested in ie 3 from the above and refer to this cell to decide how many columns to loop through.

Does this make sense?

Thanks
 
Upvote 0
If you change this line of code:
VBA Code:
    c4 = srcSht.Cells(1, Columns.Count).End(xlToLeft).Column
to this:
VBA Code:
    c4 = srcSht.Cells(1, 1).End(xlToRight).Column
instead of choosing the last column with data in row 1, it will start in column A and go out to the last column before the first blank (column G).
So I think that should do what you want.
 
Upvote 0

Forum statistics

Threads
1,224,823
Messages
6,181,181
Members
453,022
Latest member
Mohamed Magdi Tawfiq Emam

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top