Problems with copying to the next empty row - excel

I am trying to copy data from wsSource to wsDestination if the data doesn't exist in wsDestination. The data copies if the data doesn't exist but it copies to the last row rather than the next empty row.
I have attached screen shots to illustrate this
Screenshot showing data from wsDestination before any copy is done
Screenshot showing data in wsSource
Screenshot showing data in wsDestination after data has been copied
Sub test()
Dim wsSource As Worksheet, wsDestination As Worksheet
Dim LastRowSource As Long, LastRowDestination As Long
Dim i As Long, y As Long
Dim Value_1 As String, Value_2 As String, Value_3 As String
Dim ValueExists As Boolean
With ThisWorkbook
Set wsSource = .Worksheets("Data Source")
Set wsDestination = .Worksheets("Data Destination")
End With
With wsSource
'Find the last row of Column C, wsSource
LastRowSource = .Cells(.Rows.Count, "C").End(xlUp).Row
'Loop Column C, wsSource
For i = 13 To LastRowSource
'Data to be tested if it doesn't exist in wsDestination
Value_1 = .Range("B" & i).Value
Value_2 = .Range("C" & i).Value
Value_3 = .Range("D" & i).Value
ValueExists = False
With wsDestination
'Find the last row of Column B, wsDestination
LastRowDestination = .Cells(.Rows.Count, "B").End(xlUp).Row
'Loop Column B, wsDestination
For y = 5 To LastRowDestination
'Check to see whether data exists
If .Range("B" & y).Value = Value_1 Then
ValueExists = True
Exit For
End If
Next y
'If data doesn't exist in wsDestination then copy data to next available row
If ValueExists = False Then
.Range("B" & y).Value = Value_1
.Range("C" & y).Value = Value_2
.Range("D" & y).Value = Value_3
End If
End With
Next i
End With
End Sub
Screenshot 4 showing results after amended code

If I unterstood your problem, you always want to fill the next empty range on the destination sheet. First of all check this line:
For y = 5 To LastRowDestination
This loop will start from row number 5 which is the header row on the destination sheet. You don't want to accidentally overwrite it, so you start the loop from the 6th row like this:
For y = 6 To LastRowDestination
This line will check your rows to the last row on your destination sheet. So if every empty row has been filled, it will go to your last (not empty) row:
LastRowDestination = .Cells(.Rows.Count, "B").End(xlUp).Row
You want to check + 1 row (it will be a guaranteed empty row).
LastRowDestination = .Cells(.Rows.Count, "B").End(xlUp).Row + 1
You don't need ValueExists flag, you can check if a range is empty like this:
If WorksheetFunction.CountA(.Range("B" & y & ":D" & y)) = 0 Then ' EMPTY RANGE
So here is the cleaned up version of your code:
Sub test()
Dim wsSource As Worksheet, wsDestination As Worksheet
Dim LastRowSource As Long, LastRowDestination As Long
Dim i As Long, y As Long
With ThisWorkbook
Set wsSource = .Worksheets("Data Source")
Set wsDestination = .Worksheets("Data Destination")
End With
With wsSource
'Find the last row of Column C, wsSource
LastRowSource = .Cells(.Rows.Count, "C").End(xlUp).Row
'Loop Column C, wsSource
For i = 13 To LastRowSource
With wsDestination
'Find the last row of Column B, wsDestination
LastRowDestination = .Cells(.Rows.Count, "B").End(xlUp).Row + 1
'Data to be tested if it doesnt exist in wsDestination
'if IsError is true, data does not exist in wsDestination
If IsError(Application.VLookup(.Range("B" & i), .Range("B6:B" & LastRowDestination), 1, False)) Then
'Loop Column B, wsDestination
For y = 6 To LastRowDestination
'Check to see whether data existsd
If WorksheetFunction.CountA(.Range("B" & y & ":D" & y)) = 0 Then ' EMPTY RANGE
.Range("B" & y) = wsSource.Range("B" & i)
.Range("C" & y) = wsSource.Range("C" & i)
.Range("D" & y) = wsSource.Range("D" & i)
Exit For
End If
Next y
End If
End With
Next i
End With
End Sub

Related

Insert row to separates group of data with header

Would anyone will be able to help me with this script please?
As it stand, this current macro separate the data once the value/text have changes and insert new row but I just cannot work it out how to include the headers once the row have been inserted.
Sub Insert Row()
Dim ws As Worksheet
Dim lr As Long
Dim i As Long
Set ws = Worksheets("Sheet1") 'the sheet with the data
lr = ws.Range("A" & Rows.Count).End(xlUp).Row 'last row with data in Column A
For i = lr - 1 To 2 Step -1
If ws.Range("A" & i).Value <> ws.Range("A" & i + 1).Value Then ws.Range("A" & i + 1).EntireRow.Insert
Next i
End Sub
Thank you in advanced.
Duplicate Headers
A Quick Fix
Sub InsertHeaders()
Const FIRST_ROW As Long = 1
Const EMPTY_ROWS As Long = 1
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long: LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim r As Long
For r = LastRow To FIRST_ROW + 2 Step -1
With ws.Cells(r, "A")
If .Value <> .Offset(-1).Value Then
.EntireRow.Resize(EMPTY_ROWS + 1).Insert
ws.Rows(1).Copy ws.Rows(.Row - 1)
End If
End With
Next r
End Sub
Please ignore my comment, as I just realize that it will be a different result if in column A there is a cell with the same value.
Example Data :
Expected result after running the sub :
Sub test()
Dim rgHdr As Range: Dim rgData As Range: Dim cell As Range
Dim i As Integer: Dim arr: Dim ins As Integer:dim sh as worksheet
Set sh = Sheets("Sheet1") 'change if needed
ins = 3 'change if needed
With sh
.Range("A1").EntireRow.Resize(ins).Insert Shift:=xlDown
Set rgHdr = .Range("A1").EntireRow.Resize(1 + ins)
Set rgData = .Range("K" & 2 + ins, .Range("K" & Rows.Count).End(xlUp))
End With
Set arr = CreateObject("scripting.dictionary")
For Each cell In rgData: arr.Item(cell.Value) = 1: Next
For i = 1 To arr.Count - 1
rgHdr.Copy
sh.Cells(rgData.Find(arr.Keys()(i), _
after:=rgData.End(xlDown)).Row, 1).Insert Shift:=xlDown
Next
sh.Range("A1").EntireRow.Resize(ins).Delete
End Sub
sh = the sheets where the data is.
ins = skip how many blank rows.
The code use "insert copied cells" method, so it make three blank rows (the value of ins) before the header, then set the first three rows as rgHdr, set the rgData from K2 down to the last row with value.
arr = unique value in column K.
then it loop to each element in arr, get the first row occurence of the found cell which value is the looped element in arr, insert the copied rgHdr to that row.
Then finally it delete those three (ins value is 3) additional blank rows.

Can't get copy to find last row of data

I had previous question on how to find the last row of data for a formula in Column A based on data in Column C. And ya'll helped me figured that portion out!
Now I'm taking it a step further, and looping through more worksheets.
The data in Column C is Copying/Pasting correctly to the next available row.
However, the formula is pasting over the first set of data in Column A, versus finding the last row.
Better yet.. is there a way to make this formula a 1 liner?? I can't seem to get that to work either.
`Dim Mkts As Worksheet
Dim ws As Worksheet
'Destination Worksheet
Set Mkts = Workbooks("Nielsen SC Template.xlsm").Worksheets("Markets")
'Copy 4Wk Data
Workbooks.Open "C:\Users\cday\OneDrive - udfinc.com\Nielsen Scorecard\4Wk Data.xlsx"
Dim Wb4 As Workbook
Set Wb4 = Workbooks("4Wk Data.xlsx")
For Each ws In Wb4.Worksheets
With ws
If .Index <> 1 Then
'Find last used row in the copy range based on data in Column A
Dim CopyLastRow4 As Long
CopyLastRow4 = .Cells(.Rows.Count, 1).End(xlUp).Row
'Find first blank row in the destination range based on data in Column C, Offset 1 Row
Dim DestLastRowC As Long
DestLastRowC = Mkts.Cells(Mkts.Rows.Count, "C").End(xlUp).Offset(1).Row
'Find last used row in the destination range based on data in Column C
Dim LastRowColumnC As Long
LastRowColumnC = .Range("C" & .Rows.Count).End(xlUp).Row
If .Index = 2 Then
'Copy and Paste Data into C3
.Range("A4:V" & CopyLastRow4).Copy Mkts.Range("C" & DestLastRowC)
'Add Dates to Column A
Dim FR As Range 'first row
Dim LR As Range 'last row
Set FR = Mkts.Range("A3")
Set LR = Mkts.Range("A" & LastRowColumnC - 1)
Range(FR, LR).Formula = "=Mid('[4Wk Data.xlsx]Report1'!$A$1, 9, 28)"
'Add Markets to Column B
Set FR = Mkts.Range("B3")
Set LR = Mkts.Range("B" & LastRowColumnC - 1)
Range(FR, LR).Formula = "=Mid('[4Wk Data.xlsx]Report1'!$A$1, 48, 13)"
End If
If .Index = 3 Then
'Copy and Paste Data into C3
.Range("A4:V" & CopyLastRow4).Copy Mkts.Range("C" & DestLastRowC)
**'Add Dates to Column A
Set FR = Mkts.Range("A" & DestLastRowC)
Set LR = Mkts.Range("A" & LastRowColumnC)
Range(FR, LR).Formula = "=Mid('[4Wk Data.xlsx]Report2'!$A$1, 9, 28)"
'Add Markets to Column B
'Set FR = Mkts.Range("B" & DestLastRowC)
'Set LR = Mkts.Range("B" & LastRowColumnC)
'Range(FR, LR).Formula = "=Mid('[4Wk Data.xlsx]Report2'!$A$1, 48, 15)"**
End If
End If
End With
Next ws
Try something like this:
Sub Test()
Dim Mkts As Worksheet, ValA1
Dim ws As Worksheet, Wb4 As Workbook, rngCopy As Range, rngDest As Range
'Destination Worksheet
Set Mkts = Workbooks("Nielsen SC Template.xlsm").Worksheets("Markets") 'ThisWorkbook ?
'Copy 4Wk Data
Set Wb4 = Workbooks.Open("C:\Users\cday\OneDrive - udfinc.com\Nielsen Scorecard\4Wk Data.xlsx")
For Each ws In Wb4.Worksheets
With ws
If .Index = 2 Or .Index = 3 Then
'range of data to be copied from ws: A4 to V[last row in colA]
Set rngCopy = .Range("A4:V" & .Cells(.Rows.Count, 1).End(xlUp).Row)
'destination for pasting in ColC
Set rngDest = Mkts.Cells(Mkts.Rows.Count, "C").End(xlUp).Offset(1)
rngCopy.Copy rngDest 'copy the data
'grab the value from A1 on Report1
ValA1 = .Range("A1").Value '<<<<<<
'fill a range starting from rngDest two columns to the
' left and the same size (# of rows) as the copied range
' using part of the value from A1
rngDest.Offset(0, -2).Resize(rngCopy.Rows.Count).Value = Mid(ValA1, 9, 28) 'ColA
'similar process for a column one to the left from rngDest
rngDest.Offset(0, -1).Resize(rngCopy.Rows.Count).Value = Mid(ValA1, 48, 13) 'ColB
End If
End With
Next ws
End Sub

Copy specific cells from sheet to sheet based on condition

'Sub CopyRowToSheet23()
Worksheets("Sheet2").Range("A2:E1000").Clear
Dim LastRowSheet1, LastRowSheet2 As Long
Dim i As Long
Application.ScreenUpdating = False
LastRowSheet2 = Worksheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Sheet2").Range("A2:E" & LastRowSheet2).ClearContents
LastRowSheet1 = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("Sheet1")
For i = 2 To LastRowSheet1 Step 1
If Cells(i, "E").Value = "YES" Then
LastRowSheet2 = Worksheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row
Rows(i).Copy Worksheets("Sheet2").Range("A" & LastRowSheet2 + 1)
End If
Next i
End With
Application.ScreenUpdating = True
Sheet3.Select
End Sub'
I´ve managed to create the code above to get all rows that have "yes" in column E. However, I´m having issues when trying to run the macro in other sheets different than Sheet1. I would like to run it in sheet3 but I haven´t found why it does not help.
Try:
Option Explicit
Sub test()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim wsRE As Long, i As Long, LastrowC As Long, LastrowE As Long, LastrowF As Long
'Set ws1
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
'Set ws2
Set ws2 = ThisWorkbook.Worksheets("Sheet2")
wsRE = ws2.Cells(ws2.Rows.Count, "E").End(xlUp).Row
'Starting from Row 2 - let us assume that their is a header
For i = 2 To wsRE
'Check if the value in column E is yes
If ws2.Range("E" & i).Value = "Yes" Then
'Find the Last row in Sheet1 Column C
LastrowC = ws1.Cells(ws1.Rows.Count, "C").End(xlUp).Row
'Copy row i, Column A from Sheet 1 and paste it in Sheet 2 after the lastrow in column C
ws2.Range("A" & i).Copy ws1.Cells(LastrowC + 1, 3)
'Find the Last row in Sheet1 Column E
LastrowE = ws1.Cells(ws1.Rows.Count, "E").End(xlUp).Row
'Copy row i, Column B from Sheet 1 and paste it in Sheet 2 after the lastrow in column E
ws2.Range("B" & i).Copy ws1.Cells(LastrowE + 1, 5)
'Find the Last row in Sheet1 Column F
LastrowF = ws1.Cells(ws1.Rows.Count, "F").End(xlUp).Row
'Copy row i ,Column C from Sheet 1 and paste it in Sheet 2 after the lastrow in column F
ws2.Range("C" & i).Copy ws1.Cells(LastrowF + 1, 6)
End If
Next i
End Sub

Excel Macro - Fetching the values of one column based on the values from other column

I need a macro to write the row values present in column A if there is a value present in column B .
For example :
Column A Column B
Arjun
Arun 12
For the above example, I need a macro which can write "Arun 12" in Sheet2 of the work book with the Headers "Name" and "Hours".Before this the macro should clear the data present in Sheet two completely.
This will copy the all rows of columns A and B from Sheet1 to Sheet2 if B is not a Null string. And also will add the headers "Name" and "Hours".
Option Explicit 'requires that every variable has to be defined before use, e.g. with a Dim statement.
Sub DoStuff_GoodPractice()
Dim lastRowSrc As Long, lastRowDest As Long, i As Long 'declare row counts as Long so all rows can be used
Dim shtSource As Worksheet, shtDestination As Worksheet
Set shtSource = ThisWorkbook.Worksheets("Sheet1") 'full qualified identification of the worksheets
Set shtDestination = ThisWorkbook.Sheets("Sheet2")
lastRowSrc = shtSource.Range("A" & shtSource.Rows.Count).End(xlUp).Row 'determine the last used row
'clear destination sheet and write headers:
shtDestination.Cells.Clear
shtDestination.Range("A1").Value = "Name"
shtDestination.Range("B1").Value = "Hours"
lastRowDest = 1 'start with row 1 as destination
For i = 1 To lastRowSrc 'loop through all used rows
If shtSource.Range("A" & i).Value <> vbNullString And _
shtSource.Range("B" & i).Value <> vbNullString Then 'check if cells are not a null string
shtSource.Range("A" & i & ":B" & i).Copy Destination:=shtDestination.Range("A" & lastRowDest + 1) 'copy current row
lastRowDest = lastRowDest + 1 'jump to the last used row in destination
End If
Next i
End Sub
This should accomplish what you're after.
Sub DoStuff()
Dim lastRow As integer, lastRowSheet2 As integer, i As Integer
Dim sheet1 As WorkSheet, sheet2 As Worksheet
Set sheet1 = Sheets("Sheet1")
Set sheet2 = Sheets("Sheet2")
lastRow = sheet1.Range("A" & Rows.Count).End(xlUp).Row
sheet2.Cells.Clear
For i = 1 To lastRow
If sheet1.Range("A" & i).Value <> "" And sheet1.Range("B" & i).Value <> "" then
lastRowSheet2 = sheet2.Range("A" & Rows.Count).End(xlUp).Row
sheet1.Range("A" & i & ":B" & i).Copy Destination:= sheet2.Range("A" & lastRowSheet2 + 1)
End If
Next i
End Sub

How to copy and paste whole columns of data from different worksheets in Excel VBA

I'm currently working on a script that is supposed to copy four columns of data from one worksheet and paste over them to another worksheet in the same workbook. Noted I only need the data from row two onwards, I have tried with column() and Range() but it doesn't seem to be working.
Below are the script which only copies one cell on second row and paste over to another cell in the target worksheet.
Sub Sample()
Dim lastRow As Long, i As Long
Dim CopyRange As Range
Dim rw As Range
Dim rw1 As Range
Dim rw2 As Range
Dim rw3 As Range
Dim des As Range
Dim des1 As Range
Dim des2 As Range
Dim des3 As Range
'~~> Change Sheet1 to relevant sheet name
With Sheets(1)
lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lastRow
If Len(Trim(.Range("A" & i).Value)) <> 0 Then
If CopyRange Is Nothing Then
Set CopyRange = .Rows(i)
Else
Set CopyRange = Union(CopyRange, .Rows(i))
Set rw = Range("P2")
Set rw1 = Range("W2")
Set rw2 = Range("C2")
Set rw3 = Range("R2")
End If
End If
Next
If Not CopyRange Is Nothing Then
Set des = Sheets(3).Range("P2")
Set des1 = Sheets(3).Range("R2")
Set des2 = Sheets(3).Range("T2")
Set des3 = Sheets(3).Range("U2")
'~~> Change Sheet2 to relevant sheet name
rw.Copy des
rw1.Copy des1
rw2.Copy des2
rw3.Copy des3
Application.CutCopyMode = False
End If
End With
End Sub
hope this helps
'// code example copies the Column A on Sheet1 into Column A2 on Sheet2.
Sub CopyFourColumns()
'// Declare your variables.
Dim wSheet1 As Worksheet
Dim wSheet2 As Worksheet
Dim wSlastRow As Long
Dim X As Long
Dim RngToCopy As Range
Dim RngToPaste As Range
'// Set here Workbook(Sheets) names
With ThisWorkbook
Set wSheet1 = Sheets("Sheet1")
Set wSheet2 = Sheets("Sheet2")
End With
'// Here lets Find the last row of data
wSlastRow = wSheet1.Range("A" & Rows.Count).End(xlUp).Row
wSlastRow = wSheet1.Range("B" & Rows.Count).End(xlUp).Row
wSlastRow = wSheet1.Range("C" & Rows.Count).End(xlUp).Row
wSlastRow = wSheet1.Range("D" & Rows.Count).End(xlUp).Row
'// Now Loop through each row
For x = 1 To wSlastRow
Set RngToPaste = wSheet2.Range("A" & (x + 1))
With wSheet1
Set RngToCopy = Union(.Range("A" & x), .Range("A" & x))
RngToCopy.copy RngToPaste
Set RngToPaste = wSheet2.Range("B" & (x + 1))
Set RngToCopy = Union(.Range("B" & x), .Range("B" & x))
RngToCopy.copy RngToPaste
Set RngToPaste = wSheet2.Range("C" & (x + 1))
Set RngToCopy = Union(.Range("C" & x), .Range("C" & x))
RngToCopy.copy RngToPaste
Set RngToPaste = wSheet2.Range("D" & (x + 1))
Set RngToCopy = Union(.Range("D" & x), .Range("D" & x))
RngToCopy.copy RngToPaste
End With
Next X
'// Simple Msg Box
MsgBox "Copy & Paste is Done."
End Sub

Resources