简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM