Search code examples
vbaexcelworksheet

Copy data from one sheet to another (same workbook) with same column names (not necessarily same order)


I have two columns Data and Data1, on worksheet named "Data". I have same column names on sheet named "MasterData". I want to read the stuff on "Data" worksheet and copy to "MasterData" based on the column names (Data & Data1). Also, let's say I have 10 data points that I copied over to "MasterData", next time I want to keep that data there, but copy new data from sheet "Data" to "MasterData", by checking for the 1st empty cell (which in this case would be Cell Number 11) in specific column. This would need to go on as "MasterData" would store all the historical data.

Sub CopyDatatoMasterData2()

    Range("A2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
    Range("A" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select

    Range("B2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "B").End(xlUp).Row
    Range("B" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select

    Range("C2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "C").End(xlUp).Row
    Range("C" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("D2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "D").End(xlUp).Row
    Range("D" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Range("E2").Select
    Sheets("Data").Select
    Range("E2").Select
    Range(Selection, Selection.End(xlDown)).Select

    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "E").End(xlUp).Row
    Range("E" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Range("F2").Select
    Sheets("Data").Select

    Range(Selection, Selection.End(xlDown)).Select

    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "F").End(xlUp).Row
    Range("F" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("G2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "G").End(xlUp).Row
    Range("G" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select

    Range("H2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "H").End(xlUp).Row
    Range("H" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select

    Range("I2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "I").End(xlUp).Row
    Range("I" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("J2").Select

    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "J").End(xlUp).Row
    Range("J" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("K2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "K").End(xlUp).Row
    Range("K" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("L2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "L").End(xlUp).Row
    Range("L" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("M2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "M").End(xlUp).Row
    Range("M" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("N2:N3").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "N").End(xlUp).Row
    Range("N" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("O2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "O").End(xlUp).Row
    Range("O" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("P2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "P").End(xlUp).Row
    Range("P" & lMaxRows + 1).Select

    ActiveSheet.Paste
    Sheets("Data").Select
    Range("Q2:Q3").Select
    Range(Selection, Selection.End(xlDown)).Select
    Application.CutCopyMode = False
    Selection.Copy
    Sheets("MasterData").Select

    lMaxRows = Cells(Rows.Count, "Q").End(xlUp).Row
    Range("Q" & lMaxRows + 1).Select

    ActiveSheet.Paste

End Sub

Solution

  • This is not a good question for Stack Overflow. This site is for programmers to help one another develop. Your question reads as: “I want a macro to do this. Write it for me.” Not a popular style of question.

    Top right of this page you will find a Help button. You will find lots of good, but general, advice behind it. In this answer I will try to give more specific advice.

    You must learn the basics of VBA. You could have answered this question yourself with very little knowledge. A few hours spent on study will quickly be repaid. Search the web for “Excel VBA tutorial”. There are many to choose from. Try a few and complete the one that is closest to your learning style. I prefer books. I visited a good library; reviewed their Excel VBA Primers; borrowed the most promising to try at home before buying the one I considered to be best as a permanent reference book.

    This site is not a good place to ask design questions. You need to break your requirement down its little steps. There are lots questions and answers here that address the individual steps of your total requirement but, as far as I know, not one that matches your complete requirement.

    You can often create a simple design just by thinking through how you would solve this problem manually:

    1. Find the last used cell in column Data of worksheet Master. Call the cell below the last used cell: Target.
    2. Find the last used cell in column Data of worksheet Data.
    3. Select from the first data cell down to the last cell.
    4. Copy the selection to cell Target.
    5. Repeat the above steps for column Data1.

    There are VBA statements that are the equivalent of steps 1 to 4. You can select and copy as separate steps in VBA but this is not good practice; there is a VBA statement that combines them which is faster and neater.

    There are several VBA statements that allow you to repeat (loop) blocks of code with different parameters to achieve slightly different effects.

    Doesn’t that look easier already? Instead of a vague description, we have a series of easy steps. I would expect any tutorial to explain how to perform these steps within the first few pages. In my code I use a few techniques that may not be at the beginning of a tutorial. I explain why I use them. For extra information, search for “Excel VBA function array” or “Excel VBA constants” or similar. Come back with questions if necessary but the more you can discover for yourself, the faster you will develop.

    Welcome to the joys of programming.

    Option Explicit
    
      ' * I have a system of naming my variabls that I have used for years. I can
      '   look at macros I wrote years ago and immediately know what all the
      '   variables. I am not asking you to like my system but to develop your own
      '   system.
      ' * My naming system using a sequence of words that get more and precise
      '   until I have a unique name.  The first word what the variable is being
      '   used for. "Col" means its associated with columns of a worksheet or a
      '   two-dimensional array. If I have multiple worksheets and/or arrays, the
      '   next word identifies whch worksheet or array.  If I have multiple
      '   columns, the next word identifies which column.
      ' * Constants make code easier to read and easiest to maintain. Instead of a
      '   literal, such as 2, you have a meaningful name, ColDataData.  Columns
      '   can be identified by code or number: A=1, B=2, C=3 and so on. I have used
      '   numbers which I normally find more convenient although I could have used
      '   codes here.
    
      Const ColDataData As Long = 2
      Const ColDataData1 As Long = 4
      Const ColMasterData As Long = 1
      Const ColMasterData1 As Long = 2
      Const RowDataFirstData As Long = 2  ' Adjust according to how many header
                                          ' rows you have in worksheet "Data"
    
    Sub AddToMasterColumn()
    
      Dim ColDataCrnt As Long
      Dim ColMasterCrnt As Long
      Dim ColsData() As Variant
      Dim ColsMaster() As Variant
      Dim InxCols As Long
      Dim Rng As Range
      Dim RowDataLast As Long
      Dim RowMasterTgt As Long
      Dim WshtData As Worksheet
      Dim WshtMaster As Worksheet
    
      ' * Processing for your two sets of columns is the same so we can use a loop
      '   with parameters so says which pair of columns each loop is to handle.
      ' * Array() is a convenient way to load an array although the array must be
      '   variant.  Since I am loading different data types (String and Long) to
      '   the same array, this is required anyway.
      ' * These two arrays MUST have the same number of elements.
      ColsData = Array(ColDataData, ColDataData1)
      ColsMaster = Array(ColMasterData, ColMasterData1)
    
      ' Debug.Assert is a convenient way of testing for program errors during
      ' development. If UBound(ColsData) and UBound(ColsMaster) are not equal,
      ' execution will stop here.
      Debug.Assert UBound(ColsData) = UBound(ColsMaster)
    
      ' I could have used Worksheets("Data") where ever I use WshtData below.
      ' Using WshtData is slightly faster and, in my view, neater. If you change
      ' names of one of the worksheets, one change here will fix the macro.
      Set WshtData = Worksheets("Data")
      Set WshtMaster = Worksheets("MasterData")
    
      For InxCols = LBound(ColsData) To UBound(ColsData)
    
        With WshtMaster
          ' Get the destination column in worksheet Master for the current loop
          ColMasterCrnt = ColsMaster(InxCols)
          ' Find the last used row in ColMasterCrnt and add one to it to get the target cell
          RowMasterTgt = .Cells(Rows.Count, ColMasterCrnt).End(xlUp).Row + 1
        End With
    
        With WshtData
          ' Get the source column in worksheet data for the current loop
          ColDataCrnt = ColsData(InxCols)
          ' Find the last used row in ColDataCrnt
          RowDataLast = .Cells(Rows.Count, ColDataCrnt).End(xlUp).Row
          ' Specify the range to be copied
          Set Rng = .Range(.Cells(RowDataFirstData, ColDataCrnt), .Cells(RowDataLast, ColDataCrnt))
        End With
    
        ' Copy data
        Rng.Copy Destination:=WshtMaster.Cells(RowMasterTgt, ColMasterCrnt)
    
      Next
    
    End Sub
    

    Additon in response to extra requirement

    I believe Function FindColumnByName() does all that you require. I have more complicated variations which I can provide if necessary. For example I have a variation that searches for multi-row headings. But let us start simple.

    You will need to delete:

    Const ColDataData As Long = 2
    Const ColDataData1 As Long = 4
    Const ColMasterData As Long = 1
    Const ColMasterData1 As Long = 2
    

    and add at the top of AddToMasterColumn:

    Dim ColDataData As Long:
    Dim ColDataData1 As Long
    Dim ColMasterData As Long
    Dim ColMasterData1 As Long
    

    and add after WshtData and and WshtMaster are set:

    ColDataData = FindColumnByName(WshtData, “Data”)
    ColDataData1 = FindColumnByName(WshtData, “Data1”)
    ColMasterData = FindColumnByName(WshtMaster, “Data”)
    ColMasterData1 = FindColumnByName(WshtMaster, “Data2”)
    

    The test routine TestFCBN shows techniques that might be useful or might be confusing at this stage of your development. Have a quick look but ignore it until later if it you have any difficulty understanding it. With my test worksheets it outputs:

    Column 2 of worksheet Data is named Data
    Column 4 of worksheet Data is named Data1
    There is no column named X in worksheet Data
    Column 1 of worksheet MasterData is named Data
    Column 2 of worksheet MasterData is named Data1 
    

    New code:

    Sub TestFCBN()
    
      Dim ColName As String
      Dim ColTgt As Long
      Dim InxTV As Long
      Dim TestValues As Variant
      Dim WshtName As String
    
      TestValues = Array("Data", "Data", "Data", "Data1", "Data", "X", _
                         "MasterData", "Data", "MasterData", "Data1")
      ' There must be an even number of values in TestValues.  The first of each
      ' pair is the name of a worksheet, the second the name of a column in that
      ' worksheet.
    
      For InxTV = LBound(TestValues) To UBound(TestValues) Step 2
    
        WshtName = TestValues(InxTV)
        ColName = TestValues(InxTV + 1)
        ColTgt = FindColumnByName(Worksheets(WshtName), ColName)
        If ColTgt = 0 Then
          Debug.Print "There is no column named " & ColName & " in worksheet " & WshtName
        Else
          Debug.Print "Column " & ColTgt & " of worksheet " & WshtName & _
                      " is named " & ColName
        End If
    
      Next
    
    End Sub
    Function FindColumnByName(Wsht As Worksheet, ColName As String) As Long
    
      ' This function scans row 1 for a cell with a value of ColName.
      ' If found, it returns the number of that column.
      ' If not found, it returns 0
    
      Dim ColCrnt As Long
      Dim ColLast As Long
    
      With Wsht
        ColLast = .Cells(1, Columns.Count).End(xlToLeft).Column
        For ColCrnt = 1 To ColLast
          If .Cells(1, ColCrnt).Value = ColName Then
            FindColumnByName = ColCrnt
            Exit Function
          End If
        Next
      End With
    
      FindColumnByName = 0
    
    End Function