Search code examples
vbaexcelcopy-paste

Macro VBA to Copy Column based on Header and Paste into another Sheet


Background: This is my first time dealing with macros. I will have two worksheets that I’ll be using. The first sheet, ‘Source’ will have data available. The second sheet, ‘Final’ will be blank and is going to be where the macro will be pasting the data I’d like it to collect from the ‘Source’ sheet.

* I want the macro to find the specified header in the ‘Source’ sheet, copy that cell containing the header all the way down to the last row of existing data (instead of the entire column), and paste it onto the ‘Final’ sheet in a specified column (A, B, C, etc.). *

The reason why I have to specify which headers to find is because the headers in the ‘Source’ sheet won’t always be in the same position, but the ‘Final’ sheet’s headers will always be in the same position – so I CAN’T just record macros copying column A in ‘Source’ sheet and pasting in column A in ‘Final’ sheet. Also, one day the ‘Source’ sheet may have 170 rows of data, and another day it may have 180 rows.

Although, it would probably be best to copy the entire column since one of the columns will have a few empty cells rather than to the last row of existing data. I’m assuming it would stop copying when it reaches the first empty cell in the column chosen which would leave out the remaining data after that empty cell in the column – correct me if I’m wrong. If copying the entire column is the best way, then, please provide that as part of the possible solution. I’ve attached an example of the before & after result I would like accomplished: Example of Result

Find Header=X, copy entire column -> Paste into A1 in ‘Final’ sheet

Find Header=Y, copy entire column -> Paste into B1 in ‘Final’ sheet

Etc..

I’m sorry if my wording isn’t accurate – I tried to explain the best I could. It’d be awesome if someone could help me out on this! Thanks!


Solution

  • I modified an answer I gave to another user with similar problem for your case, I use dictionary function in most of my data sheets so that I can shift columns around without breaking the code, the below code you can shift your columns around and it will still work

    the only main restriction is 1. your header names must be unique 2. your header name of interest must be exactly the same. i.e. your source header of interest is PETER then your Data table should have a header with PETER and it must be unique.

    Sub RetrieveData()
    
    Dim wb As Workbook
    Dim ws_A As Worksheet
    Dim ws_B As Worksheet
    
    Dim HeaderRow_A As Long
    Dim HeaderLastColumn_A As Long
    Dim TableColStart_A As Long
    Dim NameList_A As Object
    Dim SourceDataStart As Long
    Dim SourceLastRow As Long
    Dim Source As Variant
    
    Dim i As Long
    
    Dim ws_B_lastCol As Long
    Dim NextEntryline As Long
    Dim SourceCol_A As Long
    
    Set wb = ActiveWorkbook
    Set ws_A = wb.Worksheets("Sheet A")
    Set ws_B = wb.Worksheets("Sheet B")
    Set NameList_A = CreateObject("Scripting.Dictionary")
    
    With ws_A
        SourceDataStart = 2
        HeaderRow_A = 1  'set the header row in sheet A
        TableColStart_A = 1 'Set start col in sheet A
        HeaderLastColumn_A = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column  'Get number of NAMEs you have
    
        For i = TableColStart_A To HeaderLastColumn_A
            If Not NameList_A.Exists(UCase(.Cells(HeaderRow_A, i).Value)) Then  'check if the name exists in the dictionary
                 NameList_A.Add UCase(.Cells(HeaderRow_A, i).Value), i 'if does not exist record name as KEY and Column number as value in dictionary
            End If
        Next i
    
    End With
    
    
    
    
    With ws_B  'worksheet you want to paste data into
        ws_B_lastCol = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column ' Get number of DATA you have in sheet B
        For i = 1 To ws_B_lastCol   'for each data
            SourceCol_A = NameList_A(UCase(.Cells(1, i).Value))  'get the column where the name is in Sheet A from the dictionaary
    
            If SourceCol_A <> 0 Then  'if 0 means the name doesnt exists
                SourceLastRow = ws_A.Cells(Rows.Count, SourceCol_A).End(xlUp).Row
                Set Source = ws_A.Range(ws_A.Cells(SourceDataStart, SourceCol_A), ws_A.Cells(SourceLastRow, SourceCol_A))
                NextEntryline = .Cells(Rows.Count, i).End(xlUp).Row + 1 'get the next entry line of the particular name in sheet A
    
                .Range(.Cells(NextEntryline, i), _
                       .Cells(NextEntryline, i)) _
                       .Resize(Source.Rows.Count, Source.Columns.Count).Cells.Value = Source.Cells.Value
            End If
    
        Next i
    End With
    
    
    End Sub