Copying a partial row based on multiple column criteria and pasting to row based on same criteria - excel

My destination workbook (wb1) is a table with a range of A1:Q740 and has a header row, the data workbook (wb2) that I want to copy from always has the same columns A:Q with the number of rows varying.
In both workbooks, the data in columns A:F for most, but not all rows is identical. I would like to compare those columns in both worksheets, and if a given row in A:F matches the other workbook, copy the data from that row for columns G:Q from the data workbook to the row with matching data in the destination workbook.
My issue is most of the time the rows between the two workbooks don't line up. For example, in both workbooks cells A2:F2 match. However, the farther down the workbook you go the rows diverge. In the data workbook, cells A153:F153 are the same as the destination workbook cells A159:F159. So, in this example I would like my code to copy data from cells G2:Q2 and G153:Q153 and paste them to the destination workbook in cells G2:Q2 and G159:Q159, respectively.
I've got my workbooks, worksheets and ranges named, but I'm not sure how best to run the comparison or how to code the copy/paste destination correctly.
EDIT: Updated code as below, it works until row 34 and then breaks since the matching data is no longer in the same row number in each workbook.
Option Explicit
Sub MergeWorksheets()
Dim wb1 As Workbook '2017 Tracking Report
Dim wb2 As Workbook 'Book# Drake Export from CSM
Dim Drake17 As Worksheet
Dim ImportDataFull As Range 'Full Range of Drake17 Export, less header row
Dim lastRow As Long 'Last Row of Drake17 Worksheet
Dim lastRow2 As Long 'Last Row of Drake Export
Dim ImportData As Range 'Drake Export Data
Dim DesImportData As Range 'Destination Range of Data for Compare
Dim DesImportRange As Range 'Destination for ImportRange
Set wb1 = Workbooks("2017 Tracking Report.xlsm")
Set wb2 = Workbooks(Workbooks.Count) 'Sets the most recently opened WB
Set Drake17 = wb1.Sheets("Drake17")
lastRow = Drake17.Range("A" & Rows.Count).End(xlUp).Row
Set DesImportData = Drake17.Range("A1:F" & lastRow)
Set DesImportRange = Drake17.Range("G1:Q" & lastRow)
wb2.Activate
lastRow2 = Range("A" & Rows.Count).End(xlUp).Row
Set ImportDataFull = Range("A1:Q" & lastRow2) 'Full Data Export Less Header Row
Set ImportData = Range("A1:F" & lastRow2) 'Sets range of data to compare
Dim r As Range
Dim i As Integer
With Columns(6)
.NumberFormat = "m/d/yyy"
.Value = .Value
End With
With Columns(2)
.NumberFormat = "General"
.Value = .Value
End With
Application.ScreenUpdating = False
For i = 2 To lastRow2
With ImportDataFull
Set r = Range("G" & i, "Q" & i)
If ImportData.Cells(i, 1) = DesImportData.Cells(i, 1) And _
ImportData.Cells(i, 2) = DesImportData.Cells(i, 2) And _
ImportData.Cells(i, 3) = DesImportData.Cells(i, 3) And _
ImportData.Cells(i, 4) = DesImportData.Cells(i, 4) And _
ImportData.Cells(i, 5) = DesImportData.Cells(i, 5) And _
ImportData.Cells(i, 6) = DesImportData.Cells(i, 6) Then
r.Copy DesImportRange.Rows(i)
r.EntireRow.HorizontalAlignment = xlCenter
End If
End With
Next i
Application.ScreenUpdating = True
End Sub

Related

VBA code that uses checkbox to copy and paste entire row with data to a new sheet

I have a workbook that contains several sheets with different types of inventory and one summary sheet.
I am trying to use checkboxes, that if checked as "True", will copy that row of data and paste into the summary sheet starting on a specific row. Each inventory sheet has several rows of differing data and I'd like users to be able to check multiple boxes they need on each sheet and this data to be copied to the summary sheet.
I found this code below that is working for the most part except it skips over some lines of data that are marked as "true". It also adds an unnecessary extra row between the lines once it copies the data over to the new sheet. What can I change so that all of the data marked "true" can be copied over and eliminate the extra rows?
Code I found is from this video: https://www.youtube.com/watch?v=TJoRUwrEe0g
Sub CopyRowBasedOnCellValue()
Dim xRg As Range
Dim xCell As Range
Dim A As Long
Dim B As Long
Dim C As Long
A = Worksheets("Exterior Items").UsedRange.Rows.Count
B = Worksheets("Customer Sheet").UsedRange.Rows.Count
If B = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Customer Sheet").UsedRange) = 0 Then B = 0
End If
Set xRg = Worksheets("Exterior Items").Range("B1:B" & A)
On Error Resume Next
Application.ScreenUpdating = False
For B = 1 To xRg.Count
If CStr(xRg(B).Value) = "True" Then
xRg(B).EntireRow.Copy Destination:=Worksheets("Customer Sheet").Range("A" & B + 9)
B = B + 1
End If
Next
Application.ScreenUpdating = True
End Sub
Try this:
Sub Copy_table_where_B_is_TRUE_row_by_row()
'declarations
Dim shtSource As Worksheet
Dim shtDestination As Worksheet
'reference source and destination sheets
Set shtSource = Worksheets("Exterior Items")
Set shtDestination = Worksheets("Customer Sheet")
'find limits of tables present on source and destination sheets
LastRowSource = shtSource.Cells(shtSource.Rows.Count, "A").End(xlUp).Row
LastRowDestination = shtDestination.Cells(shtDestination.Rows.Count, "A").End(xlUp).Row
'set output row index
OutputRow = LastRowDestination + 1
'using the source table..
For Each rw In shtSource.Range("1:" & LastRowSource).Rows
'if 2nd cell in row is TRUE
If rw.Cells(2).Value = "True" Then
'copy to destination sheet
rw.Copy shtDestination.Cells(OutputRow, 1)
'increment output row index
OutputRow = OutputRow + 1
End If
Next
End Sub
An entirely different method, that doesn't require any loops or counters would be to use a filter:
Sub Copy_filtered_table_where_B_is_TRUE()
'declarations
Dim shtSource As Worksheet
Dim shtDestination As Worksheet
'reference source and destination sheets
Set shtSource = Worksheets("Exterior Items")
Set shtDestination = Worksheets("Customer Sheet")
'find limits of tables present on source and destination sheets
'(these can be manually set if source table is fixed and destination location is fixed)
LastRowSource = shtSource.Cells(shtSource.Rows.Count, "A").End(xlUp).Row
LastRowDestination = shtDestination.Cells(shtDestination.Rows.Count, "A").End(xlUp).Row
'using the source table..
With shtSource.Range("1:" & LastRowSource)
'apply a filter
.AutoFilter
'set filter to column 2 = True
.AutoFilter Field:=2, Criteria1:="True"
'copy cells visible after application of filter, to next available row on destination sheet
.SpecialCells(xlCellTypeVisible).Copy shtDestination.Cells(LastRowDestination + 1, 1)
'remove filter
shtSource.AutoFilterMode = False
End With
End Sub

Excel file crashes and closes when I run the code, but results of the code who when I reopen the file

I am copying data under columns with matching headers between the source sheet and the destination sheet. Both the sheets are in the same excel file but they need to have a clarification number.
For example, one of the columns in the destination sheet has the the clarification number QM6754 and the row of data of QM6754. The source sheet also has the clarification number column but I dont want to copy it, I want to copy the other data in the row of this specific clarification number to the destination sheet that in one of its columns. this way the data isn't copied randomly and the entire row from each sheet relate to each other.
The code I used shows results(I modified it) but when I run it, the excel file shows (not responding) for about 3-4 minutes and then shutsdown or leaves a blank Excel sheet and VBA window. I close the excel file and reopen it and the data has been copied. The file is quite large and I have three pushbuttons that run this code for each sheet I want to copy data from. Three sheets with average of 3k-6k rows. But I cannot eliminate the rows.
The code runs but I would like to optimize of the way it runs because it isn't practical to run, close file and then open file again. Could the issue be with the For loop?
Sub CopyColumnData()
Dim wb As Workbook
Dim myworksheet As Variant
Dim workbookname As String
' DECLARE VARIABLES
Dim i As Integer ' Counter
Dim j As Integer ' Counter
Dim colsSrc As Integer ' PR Report: Source worksheet columns
Dim colsDest As Integer ' Open PR Data: Destination worksheet columns
Dim rowsSrc As Long ' Source worksheet rows
Dim WsSrc As Worksheet ' Source worksheet
Dim WsDest As Worksheet ' Destination worksheet
Dim ws1PRRow As Long, ws1EndRow As Long, ws2PRRow As Long, ws2EndRow As Long
Dim searchKey As String, foundKey As String
workbookname = ActiveWorkbook.Name
Set wb = ThisWorkbook
myworksheet = "Sheet 1 copied Data"
wb.Worksheets(myworksheet).Activate
' SET VARIABLES
' Source worksheet: Previous Report
Set WsSrc = wb.Worksheets(myworksheet)
Workbooks(workbookname).Sheets("Main Sheet").Activate
' Destination worksheet: Master Sheet
Set WsDest = Workbooks(workbookname).Sheets("Main Sheet")
'Adjust incase of change in column in both sheets
ws1ORNum = "K" 'Clarification Number
ws2ORNum = "K" 'Clarification Number
' Setting first and last row for the columns in both sheets
ws1PRRow = 3 'The row we want to start processing first
ws1EndRow = WsSrc.UsedRange.Rows(WsSrc.UsedRange.Rows.Count).Row
ws2PRRow = 3 'The row we want to start search first
ws2EndRow = WsDest.UsedRange.Rows(WsDest.UsedRange.Rows.Count).Row
For i = ws1PRRow To ws1EndRow ' first and last row
searchKey = WsSrc.Range(ws1ORNum & i)
'if we have a non blank search term then iterate through possible matches
If (searchKey <> "") Then
For j = ws2PRRow To ws2EndRow ' first and last row
foundKey = WsDest.Range(ws2ORNum & j)
' Copy result if there is a match between PR number and line in both sheets
If (searchKey = foundKey) Then
' Copying data where the rows match
WsDest.Range("AI" & j).Value = WsSrc.Range("A" & i).Value
WsDest.Range("AJ" & j).Value = WsSrc.Range("B" & i).Value
WsDest.Range("AK" & j).Value = WsSrc.Range("C" & i).Value
WsDest.Range("AL" & j).Value = WsSrc.Range("D" & i).Value
WsDest.Range("AM" & j).Value = WsSrc.Range("E" & i).Value
WsDest.Range("AN" & j).Value = WsSrc.Range("F" & i).Value
WsDest.Range("AO" & j).Value = WsSrc.Range("G" & i).Value
WsDest.Range("AP" & j).Value = WsSrc.Range("H" & i).Value
Exit For
End If
Next
End If
Next
'Close Initial PR Report file
wb.Save
wb.Close
'Pushbuttons are placed in Summary sheet
'position to Instruction worksheet
ActiveWorkbook.Worksheets("Summary").Select
ActiveWindow.ScrollColumn = 1
Range("A1").Select
ActiveWorkbook.Worksheets("Summary").Select
ActiveWindow.ScrollColumn = 1
Range("A1").Select
End Sub
To increase the speed and reliability, you will want to handle the copy/paste via array transfer instead of the Range.Copy method. Given your existing code, here's how a solution that should work for you:
Sub CopyColumnData()
'Source data info
Const sSrcSheet As String = "Sheet 1 copied Data"
Const sSrcClarCol As String = "K"
Const lSrcPRRow As Long = 3
'Destination data info
Const sDstSheet As String = "Main Sheet"
Const sDstClarCol As String = "K"
Const lDstPRRow As Long = 3
'Set variables based on source and destination
On Error Resume Next
Dim wbSrc As Workbook: Set wbSrc = ThisWorkbook
Dim wsSrc As Worksheet: Set wsSrc = wbSrc.Worksheets(sSrcSheet)
Dim wbDst As Workbook: Set wbDst = ActiveWorkbook
Dim wsDst As Worksheet: Set wsDst = wbDst.Worksheets(sDstSheet)
On Error GoTo 0
'Verify source and destination were found
If wsSrc Is Nothing Then
MsgBox "Worksheet """ & sSrcSheet & """ not found in " & wbSrc.Name
Exit Sub
End If
If wsDst Is Nothing Then
MsgBox "Worksheet """ & sDstSheet & """ not found in " & wbDst.Name
Exit Sub
End If
'Setup variables to handle Clarification Number matching and data transfer via array
Dim hDstClarNums As Object: Set hDstClarNums = CreateObject("Scripting.Dictionary") 'Clarification Number Matching
'Load Source data into array
Dim rSrcData As Range: Set rSrcData = wsSrc.Range(sSrcClarCol & lSrcPRRow, wsSrc.Cells(wsSrc.Rows.Count, sSrcClarCol).End(xlUp))
Dim aSrcClarNums() As Variant: aSrcClarNums = rSrcData.Value
Dim aSrcData() As Variant: aSrcData = Intersect(rSrcData.EntireRow, wsSrc.Columns("A:H")).Value 'Transfer data from columns A:H
'Prepare dest data array
Dim rDstData As Range: Set rDstData = wsDst.Range(sDstClarCol & lDstPRRow, wsDst.Cells(wsDst.Rows.Count, sDstClarCol).End(xlUp))
Dim aDstClarNums() As Variant: aDstClarNums = rDstData.Value
Dim aDstData() As Variant: aDstData = Intersect(rDstData.EntireRow, wsDst.Columns("AI:AP")).Value 'Destination will be into columns AI:AP
'Use dictionary to perform Clarification Number matching
Dim vClarNum As Variant
For Each vClarNum In aDstClarNums
If Not hDstClarNums.Exists(vClarNum) Then hDstClarNums.Add vClarNum, hDstClarNums.Count + 1
Next vClarNum
'Transfer data from source to destination using arrays
Dim i As Long, j As Long
For i = 1 To UBound(aSrcClarNums, 1)
For j = 1 To UBound(aSrcData, 2)
If hDstClarNums.Exists(aSrcClarNums(i, 1)) Then aDstData(hDstClarNums(aSrcClarNums(i, 1)), j) = aSrcData(i, j)
Next j
Next i
'Output to destination
Intersect(rDstData.EntireRow, wsDst.Columns("AI:AP")).Value = aDstData
'Save and close source workbook (uncomment next line if this is necessary)
'wbSrc.Close SaveChanges:=True
'Activate summary sheet, cell A1 in destination workbook (uncomment these lines if this is necessary)
'wbDst.Worksheets("Summary").Activate
'wbDst.Worksheets("Summary").Range("A1").Select
End Sub

While using a For Each loop in VBA, the data gets duplicated multiple times

I am trying to upload the data to the destination workbook from the source workbook.
Let's assume I have 15-20 rows of data.
There are two conditions:
When the frmData.txtdate.Value (textbox value from the userform) is = to the destination workbook's cell value, then there will be a MsgBox displaying that the data is already copied. Also I want that if this gets executed then the destination workbook should get closed.
When the frmData.txtdate.Value (textbox value from the userform) is = to the source workbook's cell value , then the whole data from range A2:T999 would get copied and pasted to the destination workbooks range A:Lastrow
But when I try doing it, all the 15-20 rows get duplicated and copied for 15-20 times below each other.
The code is as follows:
Private Sub Upload()
Dim SourceWB As Workbook
Dim SourceWs As Worksheet
Dim DesWB As Workbook
Dim DesWs As Worksheet
Dim DateRange As Range
Dim DesDataRange As Range
Dim LastRowCount As Long 'Upload Button Value
Dim DesLastRow As Long
Dim Ls As Long
Dim Y As Long
Set SourceWB = ThisWorkbook
Set SourceWs = SourceWB.Worksheets("Database")
Set DesWB = ActiveWorkbook
Set DesWs = DesWB.ActiveSheet
LastRowCount = SourceWs.Range("D" & Rows.count).End(xlUp).Row
DesLastRow = DesWs.Range("D" & Rows.count).End(xlUp).Row
Set DateRange = SourceWs.Range("D2", "D" & LastRowCount)
Set DesDateRange = DesWs.Range("D2", "D" & DesLastRow)
'Check Destination File for Similar Date
For Each Cell In DesDateRange
If Cell.Value = frmData.txtdate.Value Then
MsgBox "Data Already Colated, If you want To make any Changes Contact your SME Or Admin"
Exit Sub
End If
Next Cell
'Paste Similar Date Values to destination file
'*The problem starts here*
For Each Cell In DateRange
If Cell.Value = frmData.txtdate.Value Then
'Y = Cell.Row 'Cells(y, 1), Cells(y, 20)
SourceWs.Range("A" & 2, "T" & LastRowCount).Copy
Workbooks(FileNameValue).Activate
Ls = ActiveWorkbook.Worksheets("Sheet1").Range("A" & Rows.count).End(xlUp).Row
ActiveWorkbook.Worksheets("Sheet1").Range("A" & Ls + 1).PasteSpecial Paste:=xlPasteValues 'AndNumberFormats
End If
Next
ActiveWorkbook.Save
ActiveWorkbook.Close
End Sub
In that last for-loop you are:
Going through each cell in a column of SourceWS
For Each Cell In DateRange
Each time copying the whole Source Range
If Cell.Value = frmData.txtdate.Value Then
SourceWs.Range("A" & 2, "T" & LastRowCount).Copy
Workbooks(FileNameValue).Activate
Ls = ActiveWorkbook.Worksheets("Sheet1").Range("A" & Rows.count).End(xlUp).Row
ActiveWorkbook.Worksheets("Sheet1").Range("A" & Ls + 1).PasteSpecial Paste:=xlPasteValues 'AndNumberFormats
End If
Therefore, if more than one cell in DateRange equal the value in txtdate, the whole SourceRange will be copyied (that many times).
So the result you are describing is exactly what is coded.
Now if you want to copy the range only once you have two options:
a) Easiest with the code you have: add an Exit For within right after pasting the range.
b) Best Practice: instead of the For each Cell in DateRange loop, do something like:
Dim rn_found
Set rn_found = DateRange.find(frmData.txtdate.Value)
If Not rn_found Is Nothing Then
'... do your thing
End If

How to copy data from 2 cells from workbook A and copy to workbook B in a cell and how do I start a for loop until last row/column

I have two questions
How to combine data using two of the cells from workbookA and copy to workbookB on the same cell?
How do I start using for loop to copy it until the last row/column?
I have no clue on how to combine the data and I do not know where to place the variable inside the code for it to loop until its last column.
Dim Tlastrow As Integer
Tlastrow = Cells(1, Columns.Count).End(xlToLeft).Column
For r = 1 To Tlastrow
Workbooks("InputB.xls").Worksheets("HC_MODULAR_BOARD_20180112").Range("F3:G3").Copy _
Workbooks("Output.xls").Worksheets("Sheet1").Range("I3")
Next
Try this:
Option Explicit
Sub Paste()
Dim wsInput As Worksheet, wsOutput As Worksheet, LastRow As Long, C As Range
Set wsInput = Workbooks("InputB.xls").Worksheets("HC_MODULAR_BOARD_20180112")
Set wsOutput = Workbooks("Output.xls").Worksheets("Sheet1")
With wsInput
LastRow = .Cells(.Rows.Count, "E").End(xlUp).Row 'Last Row with data
For Each C In .Range("F3:F" & LastRow) 'loop for every row with data
wsOutput.Cells(C.Row, "I").Value = C & " " & C.Offset(0, 1)
Next C
End With
End Sub
This code is assuming you want to paste every row from your input workbook to the output workbook on the same rows, but merging F and G columns. It's just pasting the values, not formulas or formats.

Transferring Cell Values Between Worksheets | Str Looper

Intended Result
If a row in a table contains any of the listed strings in column L on Sheet1, Then copy the entire row from Sheet1 and paste the row into a duplicate table on Sheet2 (which would be blank at the beginning).
(UNINTERESTED, UNRELATED, UNDECIDED, etc...)
Then delete the entire row that was transferred from sheet 1.
After macro runs, the new transfers should not reset table on Sheet2, rather add rows on the pre-existing lines. This document would be utilized over months.
Variables
Sheet1 is named Pipeline_Input
Sheet2 is named Closed_Sheet
Sheet1 table is named tblData
Sheet2 table is named tblClosed
Images
Image 1 is the code with error
Image 2 is Sheet 1 with some picture explanation
Image 3 is Sheet 2 with some picture explanation
Current Result
Run-time error '1004':
Application-defined or object-defined error
Sub closedsheet()
Application.ScreenUpdating = False
Dim Pipeline_input As Worksheet 'where is the data copied from
Dim Closed_Sheet As Worksheet 'where is the data pasted to
Dim strPhase() As String
Dim i As Integer
Dim intPhaseMax As Integer
Dim lngLstRow As Long
Dim rngCell As Range
Dim finalrow As Integer
Dim lr As Long 'row counter
Dim Looper As Integer
intPhaseMax = 6
ReDim strPhase(1 To intPhaseMax)
strPhase(1) = "LOST"
strPhase(2) = "BAD"
strPhase(3) = "UNINTERESTED"
strPhase(4) = "UNRELATED"
strPhase(5) = "UNDECIDED"
strPhase(6) = "BUDGET"
'set variables
Set Pipeline_input = Sheet1
Set Closed_Sheet = Sheet2
lr = Range("A" & Rows.Count).End(xlUp).Row
For Looper = LBound(strPhase) To UBound(strPhase)
For i = lr To 6 Step -1
Next
If Not Sheet1.Range("L9:L300" & lngLstRow).Find(strPhase(Looper), lookat:=xlWhole) Is Nothing Then
Range(Cells(i, 1), Cells(i, 20)).Copy
Sheet2.Range("A" & Rows.Count).End(3)(2).PasteSpecial xlPasteValues
Range(Cells(i, 1), Cells(i, 20)).Delete
End If
Next
Sheet2.Select
Sheet2.columns.AutoFit
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Okay, there were a plethora of issues with the code you posted, but I decided to help you out here - Notice a few things - There's no copying and pasting here - we're just transferring data.
Secondly, use easy to understand variables. lr and lngLastRow can't be distinguished from one another, so classify them by which worksheet you're getting that value from.
We create an array in one fell swoop here - Just declare a variant and place our values in. ARRAYS (TYPICALLY) START AT ZERO, NOT ONE, so our loop starts at 0 :). Again, this is what's known as best practice...
I swapped out Looper for j. Again, keep. it. simple!
EDIT: I tested this code out on a simulated workbook and it worked fine - should run into no issues for you either.
EDIT2: Also, always use Option Explicit!
Option Explicit
Sub closedsheet()
Application.ScreenUpdating = False
Dim Pipeline_Input As Worksheet 'source sheet
Dim Closed_Sheet As Worksheet 'destination sheet
Dim i As Long, j As Long, CSlastrow As Long, PIlastrow As Long
Dim strPhase As Variant
'Here we create our array
strPhase = Array("LOST", "BAD", "UNINTERESTED", "UNRELATED", "UNDECIDED", "BUDGET")
'Assign worksheets
Set Pipeline_Input = ActiveWorkbook.Worksheets("Pipeline_Input")
Set Closed_Sheet = ActiveWorkbook.Worksheets("Closed_Sheet")
PIlastrow = Pipeline_Input.Range("A" & Rows.Count).End(xlUp).Row
For j = 0 To UBound(strPhase)
For i = PIlastrow To 6 Step -1
If Pipeline_Input.Range("L" & i).Value = strPhase(j) Then
'Refresh lastrow value
CSlastrow = Closed_Sheet.Range("A" & Rows.Count).End(xlUp).Row
'Transfer data
Closed_Sheet.Range("A" & CSlastrow + 1 & ":S" & CSlastrow + 1).Value = _
Pipeline_Input.Range("A" & i & ":S" & i).Value
'Delete the line
Pipeline_Input.Range("A" & i & ":S" & i).EntireRow.Delete
End If
Next i
Next j
Closed_Sheet.Select
Closed_Sheet.Columns.AutoFit
Application.ScreenUpdating = True
End Sub

Resources