VBA - copying unique values into different sheet - excel

Hoping you can help, please!
So I have 2 worksheets, 1 & 2. Sheet1 has already existing data, Sheet2 is used to dump raw data into. This is updated daily, and the data dump includes both data from previous days, as well as new data. The new data may include rows relating to interactions that may have happened earlier in the month, not just the previous day. So the data is not "date sequential".
There are 9 columns of data, with a unique identifier in column I.
What I'm needing to happen is when running the macro, it looks in column I in Sheet1 and Sheet2, and only copies and pastes rows where the unique identifier in Sheet 2 doesn't already exist in Sheet1. And pastes them from the last empty row onwards in Sheet1.
What I currently have is this - it's all I could find online:
Sub CopyData()
Application.ScreenUpdating = False
Dim LastRow As Long
LastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim rng As Range
Dim foundVal As Range
For Each rng In Sheets("Sheet2").Range("A1:I" & LastRow)
Set foundVal = Sheets("Sheet1").Range("I:I").Find(rng, LookIn:=xlValues, LookAt:=xlWhole)
If foundVal Is Nothing Then
rng.EntireRow.Copy Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
Next rng
Application.ScreenUpdating = True
End Sub
But it's just not working - not only does it not recognise if the value in column I already exists, it's copying and pasting only the first 2 rows from Sheet2, but duplicating them 8 times each!
Apologies in advance, I'm a real VBA novice, and just can't work out where it's all going wrong. I would appreciate any assistance!

This will do what you want:
Sub testy()
Dim wks As Worksheet, base As Worksheet
Dim n As Long, i As Long, m As Long
Dim rng As Range
Set wks = ThisWorkbook.Worksheets(2) 'Change "2" with your input sheet name
Set base = ThisWorkbook.Worksheets(1) 'Change "1" with your output sheet name
n = base.Cells(base.Rows.Count, "A").End(xlUp).Row
m = wks.Cells(wks.Rows.Count, "A").End(xlUp).Row
For i = 2 To m
On Error Resume Next
If IsError(WorksheetFunction.Match(wks.Cells(i, 9), base.Range("I:I"), 0)) Then
Set rng = wks.Cells(i, 1).Resize(1, 9) 'Change 9 with your input range column count
n = n + 1
base.Cells(n, 1).Resize(rng.Rows.Count, rng.Columns.Count).Value = rng.Value
End If
Next i
End Sub

Related

Use VBA to copy entire row from one excel worksheet to another if match is not found in Column A

I have been running into some issues trying to use VBA to compare 2 tables in different worksheets, and then copy any rows in the "Master" sheet that are not found in the "New" sheet. Both tables are formatted as tables. The match is based on an "ID" column in Column A of both tables. If an ID is in the "Master" sheet, but not in the "New" sheet, than that entire row should be copy and pasted to the end of the table in the "New" sheet.
I updated some code found in another forum, which is almost working. However, it only seems to paste over the ID data into Column A, and not the entire corresponding row of data which is needed.
Sub compare()
Dim i As Long
Dim lrs As Long
Dim lrd As Long
With Worksheets("Master")
lrs = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To lrs 'assumes header in row 1
If Application.IfError(Application.Match(.Cells(i, 1), Worksheets("New").Columns(1), 0), 0) = 0 Then
lrd = Worksheets("New").Cells(Worksheets("test").Rows.Count, 1).End(xlUp).Row
Worksheets("New").Cells(lrd + 1, 1).Value = .Cells(i, 1).Value
End If
Next i
End With
End Sub
I think the issue has to do with the "Cells" reference, instead of a range, but I do not know how to make that line dynamic.
Slightly different approach, but you need to use something like Resize() to capture the whole row, and not just the cell in Col A.
Sub compare()
Const NUM_COLS As Long = 10 'for example
Dim wb As Workbook, wsSrc As Worksheet, wsDest As Worksheet
Dim c As Range, cDest As Range
Set wb = ThisWorkbook 'or ActiveWorkbook for example
Set wsSrc = wb.Worksheets("Master")
Set wsDest = wb.Worksheets("New")
Set cDest = wsDest.Cells(Rows.Count, 1).End(xlUp).Offset(1) 'next empty row
For Each c In wsSrc.Range("A2:A" & wsSrc.Cells(Rows.Count, 1).End(xlUp).Row).Cells
If IsError(Application.Match(c.Value, wsDest.Columns(1), 0)) Then
cDest.Resize(1, NUM_COLS).Value = c.Resize(1, NUM_COLS).Value
Set cDest = cDest.Offset(1) 'next row
End If
Next c
End Sub

VBA checking for value (shell-ID) from Sheet1 and Sheet2

VBA checking for value (shell-ID) from Sheet1 and Sheet2.
So, I am a complete beginner to VBA. Yet, I have been trying to figure out the code for this using various internet sources. So my idea for this is that i have two sheets of data (say sheet1 and sheet2). Sheet1 is the master list and sheet2 has all the major data. Now, my main conditions are that if the Shell-ID of a specific row in sheet1 matches the Shell-ID in sheet2, then just update the phase of the project. But if the value does not exist, then copy other columns like name of the project, project description, phase of the project etc. for that corresponding shell-ID back into sheet1 from sheet2.
So far, I can only make the entire row copied onto the sheet but not specific parts that I require. Here is my code and what I have tried. Any help will be appreciated.
Edit: for some reason I cannot attach files to stack (dont know if its possible to be honest) but I have added the pictures for the sheet
Sub Copying()
'defining the variables
Dim sh1 As Worksheet, sh2 As Worksheet, lr As Long, fn As Range, sr As Range, rng As Range, n As Long
Dim i As Long, j As Long
Set sh1 = Sheet1
Set sh2 = Sheet2
Application.ScreenUpdating = False
'counting the number of rows in sheet 1
With Worksheets("Sheet1")
lr = .Cells(Rows.Count, 1).End(xlUp).Row + 1
End With
'gives you the number of rows
MsgBox ("Sheet1 has " & lr & "rows")
'counting rows for sheet2
With Worksheets("Sheet2")
j = .Cells(Rows.Count, 1).End(xlUp).Row
End With
'gives the number of rows for sheet2
MsgBox ("Sheet2 has " & j & "rows")
'checking the value from sheet2 vs sheet1 for shell ID #, if not present then it will copy the entire row
For i = 2 To j
With Worksheets("Sheet2")
If .Cells(i, 1).Value <>
Worksheets("Sheet1").Cells(i, 1).Value Then
.Rows(i).Copy
Destination:=Worksheets("Sheet1").Range("A" & lr)
lr = lr + 1
ElseIf .Cells(i, 1).Value =
Worksheets("Sheet1").Cells(i, 1).Value Then
End If
End With
Next i
MsgBox ("Copying complete")
End Sub

Copy and Paste under specific Header

I have 6 different headers under the WIPTX worksheet that will be pulling information from the TestData tab which is essentially data that will be uploaded from a SharePoint site. I want to be able to copy and paste rows that have specific values like the type of status or by name
under each header in the WIPTX worksheet. Headers are in columns A-C, E-G, I-K, M-O, Q-S, and U-W. Headers are of different status's that are in the TestData worksheet. Status include Assigned, Accepted, In Progress, On Hold, Completed, and Cancelled.
Will this be possible?
Code that I have so far works but it does not paste under specific header columns.
I have tried researching and looing at other sources but I am still not able to find the right code that is specific to what I am looking for.
Sub Update1()
Dim LastRow1 As Long, LastRow2 As Long, i As Long
With ThisWorkbook.Worksheets("TestData")
LastRow1 = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow1
If .Range("A" & i).Value = "Thomas Xiong" Then
LastRow2 = ThisWorkbook.Worksheets("All Projects with NetBuilds").Cells(ThisWorkbook.Worksheets("All Projects with NetBuilds").Rows.Count, "A").End(xlUp).Row
.Rows(i).Copy ThisWorkbook.Worksheets("All Projects with NetBuilds").Rows(LastRow2 + 1)
End If
Next i
End With
End Sub
Is this possible?
I think this should help you:
Option Explicit
Sub Update1()
Dim wsData As Worksheet, wsProjects As Worksheet, LastRow As Long, Col As Integer, CopyRange As Range, C As Range
With ThisWorkbook
Set wsData = .Sheets("TestData") 'refering the worksheet with all the data
Set wsProjects = .Sheets("All Projects with NetBuilds") 'refering the worksheet with the headers
End With
For Each C In wsData.Range("A2", wsData.Cells(1, 1).End(xlDown)) 'Lets assume the criteria is on the column A
With wsData
Select Case C.Value
Case "Assigned"
With wsData
Set CopyRange = .Range(.Cells(C.Row, 3), .Cells(C.Row, 5)) 'Here I'm assuming you want to copy data from Columns B To D
End With
Case "Accepted"
With wsData
Set CopyRange = .Range(.Cells(C.Row, 7), .Cells(C.Row, 9)) 'Here I'm assuming you want to copy data from Columns G To I
End With
'... all your headers
End Select
End With
With wsProjects
Col = .Cells.Find(C).Column 'Find the header column
LastRow = .Cells(.Rows.Count, Col).End(xlUp).Row + 1 'find the last row on that header
CopyRange.Copy .Cells(LastRow, Col) 'paste the range (this method will copy everything from the source)
End With
Next C
'In case you are always copying the same range of cells skip the select case, delete the CopyRange variable and just copy paste on the last block
End Sub

Paste cells to another worksheet in VBA

I want to paste cells across worksheets in VBA. In the code below, I first select the range of cells, and then paste to another worksheet. But it runs error '9": Subscript out of range. I think the problem is in the last line for copy & paste. Here's my code:
Sub MatchFRB()
' find last row and column
Dim LastRow As Long
Dim LastColumn As Long
Dim StartCell As Range
Set StartCell = Range("A1")
LastRow = Sheet22.Cells(Sheet22.Rows.Count, StartCell.Column).End(xlUp).Row
LastColumn = Sheet22.Cells(StartCell.Row, Sheet22.Columns.Count).End(xlToLeft).Column
' Select cells until meets Threshold=5000000000
Dim i As Integer
Dim Bal As Double
Threshold = 0
For i = 2 To LastRow
Bal = Threshold + Range("AV" & i)
If Threshold > 5000000000# Then
Exit For
End If
Next i
' copy cells from Sheet22 and paste to Sheet21
Sheet22.Range(StartCell, Sheet22.Cells(i, LastColumn)).Copy Worksheets("Sheet21").Range(StartCell, Sheet21.Cells(i, LastColumn))
End Sub
Many thanks!
You have to properly call to your sheet. VBA doesn't accept just the name of the sheet as an object. You have to reference to the sheet with Worksheets("Sheet22"), another option would be to set an object to be this:
Dim ws as object
set ws = Thisworkbook.Worksheets("Sheet22")
This way VBA knows you want Sheet22 from the book that the macro is in; otherwise you could specify the workbook with Workbooks("YourWorkBookName").WorkSheets("SheetName").
From there you could use ws.Range as you were doing with Sheet22. Similarly, StartCell may be a range, but it only acts with the active sheet, so it wouldn't be a bad idea to reference it to a certain sheet and/or book as well. But in this case, I've left it out because it's always A1 and that's simple enough to enter.
Later in your code when you're trying to calculate the balance, you also have to use .Value after you call your range so that you actually access the number stored in the cell. But if you're threshold is what you're checking you should be adding the threshold back to itself. However, I've chosen to just use Bal in this case because it made more sense to me.
Sub MatchFRB()
' find last row and column
Dim LastRow As Long
Dim LastColumn As Long
Dim ws as object
Dim i As Integer
Dim Bal As Double
set ws = Thisworkbook.Worksheets("Sheet22")
LastRow = ws.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
LastColumn = ws.Cells.Find("*", searchorder:=xlByColumns, searchdirection:=xlPrevious).Column
' Select cells until meets Threshold=5000000000
Bal = 0
For i = 2 To LastRow
Bal = Bal + ws.Range("AV" & i).Value
If Bal >= 5000000000 Then
Exit For
End If
Next i
' copy cells from Sheet22 and paste to Sheet21
ws.Range("A1:" & Cells(i, LastColumn).Address).Copy Worksheets("Sheet21").Range("A1:", Cells(i, LastColumn).address)
End Sub

Excel expression to copy rows but remove blank rows

I need to copy data from one worksheet into another. However, I need a conditional copy operation that will skip rows based on criteria.
For example, if I start with...
Active Value
yes 1
no 2
no 3
yes 4
no 5
no 6
I only want to copy rows that are Active=yes, so I would end up with...
Value
1
4
Can someone show me how this is done with 1) a macro and 2) a formula?
Formula approach:
suppose your data are in sheet1, range A2:B7.
Then use this formula in sheet2 cell A2:
=IFERROR(INDEX(Sheet1!B:B,SMALL(IF(Sheet1!$A$2:$A$7="yes",ROW(Sheet1!$A$2:$A$7)),ROW()-ROW($A$2)+1)),"")
with array entry (CTRL+SHIFT+ENTER) and then drag it down.
VBA approach:
You can use AutoFilter:
Sub test()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng As Range, rngToCopy As Range
Dim lastrow As Long
'change Sheet1 and Sheet2 to suit
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
Set ws2 = ThisWorkbook.Worksheets("Sheet2")
With ws1
'assumung that your data stored in column A:B, Sheet1
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A1:B" & lastrow)
'clear all filters
.AutoFilterMode = False
With rng
'apply filter
.AutoFilter Field:=1, Criteria1:="yes"
On Error Resume Next
'get only visible rows
Set rngToCopy = .SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End With
'copy range
If Not rngToCopy Is Nothing Then rngToCopy.Copy Destination:=ws2.Range("A1")
'clear all filters
.AutoFilterMode = False
End With
Application.CutCopyMode = False
End Sub
Note, if you want to copy only Value column, change
Set rngToCopy = .SpecialCells(xlCellTypeVisible)
to
Set rngToCopy = .Offset(, 1).Resize(, .Columns.Count - 1).SpecialCells(xlCellTypeVisible)
It's easy enough with a macro. Assuming you're copying from the first sheet to the second sheet, and that your sample above is in columns A and B, you could do the following:
Public Sub ConditionalCopy()
Dim copyRng As Range
Set copyRng = Worksheets(1).Range("B2:B7")
Dim pasteRng As Range
Set pasteRng = Worksheets(2).Range("A2")
Dim i As Long
i = 0
For Each cell in copyRng.Cells
If cell.Offset(0, -1).Value2 = "yes" Then
pasteRng.Offset(i,0).Value2 = cell.Value2
i = i + 1
End If
Next cell
End Sub
Doing it with a formula presents a challenge in terms of not leaving any blank rows on the second sheet. It would be pretty trivial to just use the following in the second sheet:
=If(A2 = "yes",b2,"")
And copy that down, but you're going to end up with blank rows that you'll have to go back and delete yourself. If you have the ability to use the macro, it's straightforward enough that I would go that route rather than sinking too much effort into devising a formula. The more I think about it, the more I feel like it has to be a programmatic solution to avoid double references.
If you use seperate counters for the source and destination rows, and use cell references rather than ranges the following routine should do the trick
Public Sub copyactivevalue()
Dim i As Integer
Dim j As Integer
Dim acts As Excel.Worksheet
Dim news As Excel.Worksheet
Set acts = Excel.Worksheets("sheet1")
Set news = Excel.Worksheets("sheet2")
With acts
j = 2
For i = 2 To 7
If acts.Cells(i, 1).Value = "yes" Then
news.Cells(j, 1) = acts.Cells(i, 2).Value
j = j + 1
End If
Next
End With
Set acts = Nothing
Set news = Nothing
End Sub
Hope this helps

Resources