-1

I have a user who works with Excel sheets daily. She spends a lot of time transferring data from one sheet to another and has requested that I find a script/macro/formula that could automate some of the process. I have searched around and found some scripts that look like they will do close to what we need but I am not an expert on Excel VBA scripts so I am unsure how to modify it to accomplish what we need.

I have 2 large Excel sheets, one is filled with S/N's and details and the other is filled with dates, names and time periods. What I need the script to accomplish is to run against both sheets and when it finds a matching cell from sheet 1's column A and sheet 2's column A, it will take all the data from sheet 2's matching row and append it to the end of the matching row on sheet 1.

Here is an example of what I am trying to accomplish:

SN112233 Apple
SN112244 Orange            SHEET 1
SN112255 Grape


SN112211 01/01/14 Mike 5Days
SN112222 02/02/14 Tim 2Days          SHEET 2
SN112233 05/03/14 Rick 8Days
SN112244 24/03/14 Tim 1Day
SN112255 11/04/14 Daryl 12Days

After the script has ran the data would then end up looking like this on sheet 1

SN112233  Apple  05/03/14  Rick  8 Days
SN112244  Orange 24/03/14  Tim   1 Day         SHEET 1
SN112255  Grape  11/04/14  Daryl 12 Days

Here is one of the scripts that I found that looks like it is on the right track for what I need accomplished but I am unsure how to modify it to complete everything that I need done:

Sub MatchAndCopy()

    Dim sheet01 As Worksheet, sheet02 As Worksheet
    Dim c As Range, matchingCell As Long
    Dim RangeInSheet1 As Range
    Dim RangeInSheet2 As Range
    Dim dict As Object, tmp
    Set dict = CreateObject("scripting.dictionary")

    Application.ScreenUpdating = False
    Application.DisplayStatusBar = True

    Set sheet01 = Worksheets("Sheet1")
    Set sheet02 = Worksheets("Sheet2")

    Set RangeInSheet1 = sheet01.Range(sheet01.Range("A2"), _
              sheet01.Cells(Rows.count, 1).End(xlUp))
    Set RangeInSheet2 = sheet02.Range(sheet02.Range("A2"), _
              sheet02.Cells(Rows.count, 1).End(xlUp))

    'populate dictionary...
    For Each c In RangeInSheet1.Cells
        tmp = c.Value
        If Not dict.exists(tmp) Then
            dict.Add tmp, c.Row
        End If
    Next c

    For Each c In RangeInSheet2.Cells
      tmp = c.Value
      If dict.exists(tmp) Then
        Application.StatusBar = "Please wait while data is being copied," & _
                                " Processing count : " & c.Row
        sheet01.Cells(dict(tmp), "F").Resize(1, 5).Value = _
                c.Offset(0, 1).Resize(1, 5).Value
      End If
    Next c

    Application.StatusBar = False
    Application.ScreenUpdating = True

End Sub

Any assistance with this would be greatly appreciated!

Community
  • 1
  • 1
CeeTech
  • 3
  • 1
  • 3

3 Answers3

0

Formula for sheet1 C1: =VLOOKUP(A1,SHEET2!$A$1:$D$5,2,FALSE)
Formula for sheet1 D1: =VLOOKUP(A1,SHEET2!$A$1:$D$5,3,FALSE)
Formula for sheet1 E1: =VLOOKUP(A1,SHEET2!$A$1:$D$5,4,FALSE)

And drag down

user3616725
  • 3,485
  • 1
  • 18
  • 27
  • Thank you everyone for your comments and help. Further investigation into the Vlookup function has resolved the problem I was trying to fix and looks to be the best solution. The final formula I ended up going with looks like this: =VLOOKUP(A2,SHEET2!$A$1:$N5,2,FALSE) – CeeTech Oct 23 '14 at 14:33
0

To expand on the other answer by user3616725, you can link between sheets by referring to the cell as SHEET1!$A$1. You can in turn link between entire workbooks by doing [workbook.xlsx]SHEET1!$A$1, though that requires them to be in the same folder. You can link to separate folders by specifying the aboslute path in the [workbook.xlsx] part.

Nam Taf
  • 74
  • 2
-1

I agree with the earlier answers: it appears this requirement can most easily be met with Excel formulae.

This answer is largely advice on how to develop VBA solutions when necessary.

I do not believe that searching for a large code block that appear to vaguely match your requirement and then amending that block is the correct approach. It is likely that any code block you find will contain VBA functionality you do not understand. Do you know what dictionaries are? Do you know how to use dictionaries? Would a dictionary be the right solution on this occasion?

If you are going to write VBA macros, you must learn VBA. Search the web for "Excel VBA tutorial". There are many to choose from so pick one that matching your learning style. I prefer books. I visted the library in the nearest large town and reviewed their Excel VBA primers. I borrowed a few so I could try them at home. Finally I visited a bookshop and bought the one most suitable for me. I would dip into that book whenever necessary. Whichever approach is right for you, the time spent learning VBA will quickly repay itself.

You must break your requirement down into simple steps for which you already know the VBA or for which you could expect to find some useful code in your book or if you searched the web.

You want to update one worksheet from another. In general, I never update a worksheet because if something goes wrong before the macro is finished, I have corrupted the worksheet. I normally, create a new worksheet and build it from the source worksheets. If anything goes wrong, restarting is easy. If appropriate, I will delete the original worksheet when the new one is complete. Do you know how to create a new worksheet or delete an existing one? You can search for "Excel VBA: create worksheet" and expect to find a useful answer. However, I would start the macro recorder and create some worksheets and delete them from the keyboard. I would then examine the resultant code to discover the statements that create and delete worksheets.

In this case you are adding new columns to the end of the existing rows so there would be no problem with restarting the macro.

The heart of your macro will be a loop that examines every row in Sheet1. Any book on online tutorial will show you how to do that. Searching for "Excel VBA: find last row of worksheet" will give you relevant code.

I could go on but I hope I have given you an adequate introduction to designing and creating a solution to a requirement,

There are many similar method of meeting your requirement. Which method is best is not always obvious with a small requirement so I have picked a method what I hope is easy to understand.

Option Explicit     ' Look up thi statement to see why its inclusion is good practice
Sub MergeSheets()

  ' Using constants for columns means your code:
  '  * takes longer to write
  '  * is easier to read and debug
  '  * can be updated quickly if a column moves

  ' Note my naming style. I start with what I use the variable or constant for.
  ' Eg: "Col" for column. I then add words that narrow down the use until I
  ' have a unique name. I am not asking you to like my style but to develop a
  ' style of your own. I can look at macros I wrote years ago and immediately
  ' know what all the variables are which is a big help.

  ' I have used "One" and "Two" to identify the sheets because "1" and "2" are
  ' too short. However, you should give meaningful naems to your worksheets.

  Const ColOneSN As Long = 1
  Const ColOneProduct As Long = 2
  Const ColOneDateFinished As Long = 3
  Const ColOnePerson As Long = 4
  Const ColOneDuration As Long = 5
  Const ColOneDurationUnit As Long = 6

  Const ColTwoSN As Long = 1
  Const ColTwoDateFinished As Long = 2
  Const ColTwoPerson As Long = 3
  Const ColTwoDuration As Long = 4
  Const ColTwoDurationUnit As Long = 5

  Dim DateFinished As Date
  Dim Duration As Long
  Dim DurationUnit As String
  Dim Person As String
  Dim Rng As Range
  Dim RowOneCrnt As Long
  Dim RowOneLast As Long
  Dim SN As String
  Dim WshtOne As Worksheet
  Dim WshtTwo As Worksheet

  Set WshtOne = Worksheets("Sheet1")
  Set WshtTwo = Worksheets("Sheet2")

  ' Assume column widths in WshtTwo are corect and use them for WshtOne
  WshtOne.Columns(ColOneDateFinished).ColumnWidth = WshtTwo.Columns(ColTwoDateFinished).ColumnWidth
  WshtOne.Columns(ColOnePerson).ColumnWidth = WshtTwo.Columns(ColTwoPerson).ColumnWidth
  WshtOne.Columns(ColOneDuration).ColumnWidth = WshtTwo.Columns(ColTwoDuration).ColumnWidth
  WshtOne.Columns(ColOneDurationUnit).ColumnWidth = WshtTwo.Columns(ColTwoDurationUnit).ColumnWidth

  RowOneLast = WshtOne.Cells(Rows.Count, ColOneSN).End(xlUp).Row

  ' Start value for For Loop assumes no header row as in your example.
  ' You could use a constant such as RowOneDataFirst if a header line
  ' might be added later or if the number of lines mught change.

  For RowOneCrnt = 1 To RowOneLast
    ' Extract SN to search for from WshtOne
    With WshtOne
      SN = .Cells(RowOneCrnt, ColOneSN).Value
    End With
    With WshtTwo
      ' Search SN column of WshtTwo for SN
      Set Rng = .Columns(ColTwoSN).Find(What:=SN)
      If Rng Is Nothing Then
        ' This SN not found

        ' Add code for this sitation

      Else
        ' SN found
        DateFinished = .Cells(Rng.Row, ColTwoDateFinished).Value
        Person = .Cells(Rng.Row, ColTwoPerson).Value
        Duration = .Cells(Rng.Row, ColTwoDuration).Value
        DurationUnit = .Cells(Rng.Row, ColTwoDurationUnit).Value
      End If
    End With
    If Not Rng Is Nothing Then
      ' Copy values into WshtOne
      With WshtOne
        .Cells(RowOneCrnt, ColOneDateFinished).Value = DateFinished
        .Cells(RowOneCrnt, ColOnePerson).Value = Person
        .Cells(RowOneCrnt, ColOneDuration).Value = Duration
        .Cells(RowOneCrnt, ColOneDurationUnit).Value = DurationUnit
      End With
    End If

  Next

End Sub
Tony Dallimore
  • 12,335
  • 7
  • 32
  • 61