Compare sheet 1 & 2 using column B1 as guide if not match copy row to sheet 3 - vba

I have an excel which has 3 sheets. In sheet 1 and 2 i have approximately 10 columns each but has different total number of rows. I want to check if data in Sheet 2 is in Sheet 1. If it has a match then do nothing but if it has no match then copy the entire row into sheet 3.
Here's my code But I think i got it wrong
Sub test()
Dim rng As Range, c As Range, cfind As Range
On Error Resume Next
Worksheets("sheet3").Cells.Clear
With Worksheets("sheet1")
Set rng = Range(.Range("A2"), .Range("a2").End(xlDown))
For Each c In rng
With Worksheets("sheet2")
Set cfind = .Columns("A:A").Cells.Find _
(what:=c.Value, lookat:=xlWhole)
If cfind Is Nothing Then GoTo line1
'c.EntireRow.Copy Worksheets("sheet3").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
c.Copy Worksheets("sheet3").Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
c.Offset(0, 2).Copy Worksheets("sheet3").Cells(Rows.Count, "B").End(xlUp).Offset(1, 0)
End With 'sheet 2
line1:
Next c
Application.CutCopyMode = False
End With 'sheet 1
To explain it in picture refer below
Sheet 1
Sheet 2
Sheet 3
The Sheet 3 is my expected output. Can i obtain the output such as that.
Please help.
Thanks.

Try this one "
Sub test()
Dim rng As Range, c As Range, cfind As Range
On Error Resume Next
Worksheets(3).Cells.Clear
With Worksheets(1)
Set rng = .Range(.Range("A2"), .Range("a2").End(xlDown)) 'added . (dot) in front of first range
For Each c In rng
With Worksheets(2)
Set cfind = .Columns("A:A").Cells.Find _
(what:=c.Value, lookat:=xlWhole)
If cfind Is Nothing Then
'change the "10" in "Resize(1, 10)" to the number of columns you have
c.Resize(1, 10).Copy Worksheets(3).Cells(Worksheets(3).Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
End With 'sheet 2
Next c
Application.CutCopyMode = False
End With 'sheet 1
End Sub
Edit for Avidan's question in comments
To check every row with every row on other sheet requires different approach. Such as :
Sub CopyMissingRecords()
'compare whole record in row on 1st worksheet with all records in rows on 2nd worksheet
'and if there is no such row in the 2nd worksheet, then copy the missing record to 3rd worksheet
'repeat for all records on 1st worksheet
Dim varToCopy() As Variant
Dim varToCompare() As Variant
Dim intCopyRow As Integer
Dim intCopyRowMax As Integer
Dim intToCompareRow As Integer
Dim intToCompareRowMax As Integer
Dim bytColumnsInData As Byte
Dim intMisMatchCounter As Integer
Dim intComparingLoop As Integer
Dim intRowMisMatch As Integer
bytColumnsInData = 10 ' change to your situation
'clear everything in our output columns in Worksheets(3)
With Worksheets(3)
.Range(.Cells(2, 1), .Cells(.Rows.Count, bytColumnsInData)).Clear
End With
With Worksheets(1)
'last row in Worksheets(1)
intCopyRowMax = .Cells(.Cells.Rows.Count, 1).End(xlUp).Row
'compare each row in Worksheets(1)
For intCopyRow = 2 To intCopyRowMax
'store the first row record from Worksheets(1) into memory
ReDim varToCopy(0)
varToCopy(0) = .Range(.Cells(intCopyRow, 1), .Cells(intCopyRow, bytColumnsInData))
With Worksheets(2)
'last row in Worksheets(2)
intToCompareRowMax = .Cells(.Cells.Rows.Count, 1).End(xlUp).Row
'loop through all rows in Worksheets(2)
For intToCompareRow = 2 To intToCompareRowMax
'store the actual row record from Worksheets(2) into memory
ReDim varToCompare(0)
varToCompare(0) = .Range(.Cells(intToCompareRow, 1), .Cells(intToCompareRow, bytColumnsInData))
'compare each column from the row record in Worksheets(1), with each column from the row record in Worksheets(2)
For intComparingLoop = 1 To bytColumnsInData
'if any of the cells from Worksheets(1) in compared row are different than cells from Worksheets(2) in compared row
'just one difference in row is enough to consider this record as missing
If varToCopy(0)(1, intComparingLoop) <> varToCompare(0)(1, intComparingLoop) Then
'store how many row MisMatches are there in data
intRowMisMatch = intRowMisMatch + 1
Exit For
End If
Next intComparingLoop
Next intToCompareRow 'next row in Worksheets(2)
'if there are as many row mismatches as there are row records in Worksheets(2)
If intRowMisMatch = intToCompareRowMax - 1 Then
With Worksheets(3)
'copy the entire row from Worksheets(1) to the next available row in Worksheets(3)
Worksheets(1).Range(Worksheets(1).Cells(intCopyRow, 1), Worksheets(1).Cells(intCopyRow, bytColumnsInData)).Copy _
Destination:=.Cells(.Cells.Rows.Count, 1).End(xlUp).Offset(1, 0)
End With 'Worksheets(3)
End If
'reset the counter
intRowMisMatch = 0
End With 'Worksheets(2)
Next intCopyRow 'next row in Worksheets(1)
End With 'Worksheets(1)
End Sub

Related

How do I change this statically set range to a dynamic range? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a summary sheet Consolidated Tracker and data sheets that won't be set statically as they'll be dates i.e Sheet1 renamed May 2018 Sheet2 renamed October 2018 Sheet3 renamed May 2019 etc.
The follow code checks for a match in Column B across two statically set worksheets Consolidated Tracker and May 2018.
If a match is found, it takes the value from cell C4 in May 2018 and sets C4 in the Consolidated Tracker to this value.
What I'd next like to achieve is to check:
Sheet3 and Set D4 in the Consolidated Tracker if a match is found.
Sheet4 and set E4 in the Consolidated Tracker if a match is found.
Sheet5 and set F4 in the Consolidated Tracker if a match is found.
I've got this far by myself but I'm unsure how to procede from here.
Thank you.
Option Explicit
Public Sub UpdateData()
Dim WsDest As Worksheet 'destination workbook to write in
Set WsDest = ThisWorkbook.Worksheets("Consolidated Tracker")
Dim WsSrc As Worksheet 'source workbook to match with
Set WsSrc = ThisWorkbook.Worksheets("May 2018")
Dim LastRow As Long 'last used row in workbook
LastRow = WsDest.Cells(WsDest.Rows.Count, "B").End(xlUp).Row
Dim iRow As Long, MatchedRow As Long
For iRow = 1 To LastRow 'loop through all rows from row 1 to last used row and update each row
MatchedRow = 0 'initialize
On Error Resume Next 'if no match found then ignore error
MatchedRow = WorksheetFunction.Match(WsDest.Cells(iRow, "B"), WsSrc.Columns("B"), 0) 'get the row number of the match
On Error GoTo 0 'reactivate error reporting
If MatchedRow > 0 Then 'if a match was found then copy values
WsDest.Cells(iRow, "C").Value = WsSrc.Cells(MatchedRow, "C").Value
End If
Next iRow
End Sub
Does this do what you want?
It uses the sheet index but I'm uneasy about that because sheets can easily be re-ordered and your code will blow up.
As it stands the code will run through from the first to penultimate sheet (assuming your destination sheet is last) so you might need to adjust the j loop.
Public Sub UpdateData()
Dim WsDest As Worksheet 'destination workbook to write in
Set WsDest = ThisWorkbook.Worksheets("Consolidated Tracker")
Dim LastRow As Long 'last used row in workbook
LastRow = WsDest.Cells(WsDest.Rows.Count, "B").End(xlUp).Row
Dim iRow As Long, MatchedRow As Variant, j As Long, c As Long
c = 3
For j = 1 To Sheets.Count - 1
For iRow = 1 To LastRow 'loop through all rows from row 1 to last used row and update each row
MatchedRow = Application.Match(WsDest.Cells(iRow, "B"), Worksheets(j).Columns("B"), 0) 'get the row number of the match
If IsNumeric(MatchedRow) Then 'if a match was found then copy values
WsDest.Cells(iRow, c).Value = Worksheets(j).Cells(MatchedRow, "C").Value
End If
Next iRow
c = c + 1
Next j
End Sub
Here is a better method which doesn't rely on sheet indexes.
Public Sub UpdateData()
Dim WsDest As Worksheet 'destination workbook to write in
Set WsDest = ThisWorkbook.Worksheets("Consolidated Tracker")
Dim LastRow As Long 'last used row in workbook
LastRow = WsDest.Cells(WsDest.Rows.Count, "B").End(xlUp).Row
Dim iRow As Long, MatchedRow As Variant, c As Long, ws As Long
c = 3
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> WsDest.Name Then
For iRow = 1 To LastRow 'loop through all rows from row 1 to last used row and update each row
MatchedRow = Application.Match(WsDest.Cells(iRow, "B"), ws.Columns("B"), 0) 'get the row number of the match
If IsNumeric(MatchedRow) Then 'if a match was found then copy values
WsDest.Cells(iRow, c).Value = ws.Cells(MatchedRow, "C").Value
End If
Next iRow
c = c + 1
End If
Next ws
End Sub

need vba macro to delete cells except first and last row in each column

I have a excel which has multiple rows and columns and range of column values differ for each row.
Need a macro which will delete all cells in a row except first and last in each row and paste the last value next to first value.
Tried the below script:
Sub test()
Dim sh As Worksheet
Dim IDS As range
Dim ID As range
Set sh = ThisWorkbook.Sheets("Sheet1")
Set IDS = ActiveSheet.range("A2", range("A1").End(xlDown))
For Each ID In IDS
Dim b As Integer
Dim k As Integer
k = sh.range("ID", sh.range("ID").End(xlToRight)).Columns.Count
b = k - 1
range(ID.Offset(0, 0), ID.Offset(0, "b")).Select
Selection.ClearContents
Next ID
End Sub
This is a little different approach but should help.
Also, it is generally not best to declare variables in a loop as you do with b & k just fyi
Sub test()
Dim sh As Worksheet
Dim row As Integer
Dim lastCol As Integer
Set sh = ThisWorkbook.Sheets("Sheet1")
For row = 2 To sh.Cells(Sheets(1).Rows.Count, "A").End(xlUp).row
lastCol = sh.Cells(row, Columns.Count).End(xlToLeft).Column
sh.Range("B" & row).Value = sh.Cells(row, lastCol).Value
sh.Range(sh.Cells(row, 3), sh.Cells(row, lastCol)).ClearContents
Next
End Sub
Best of luck
I'd go as follows:
Sub test()
Dim cell As Range
With ThisWorkbook.Sheets("Sheet1") ' reference relevant sheet
For Each cell In .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)) ' loop through referenced sheet column A cells from row 2 down to last not empty one
With .Range(cell, .Cells(cell.Row, .Columns.Count).End(xlToLeft)) ' reference referenced sheet range spanning from current cell to last not empty one in the same row
If .Count > 2 Then ' if referenced range has more then 2 cells
cell.Offset(, 1).Value = .Cells(1, .Count).Value ' store last cell value next to the current one
.Offset(, 2).Resize(, .Columns.Count - 1).ClearContents 'clear all cells right of current one
End If
End With
Next
End With
End Sub
You can use Range.Delete Method (Excel)
range(ID.Offset(0, 0), ID.Offset(0, b)).Delete Shift:=xlToLeft

Delete entire rows in excel sheet from a table using macro

i want to build a macro that delete rows from a table in an excel sheet based on an if statement that runs on all the rows from row number 2 to the end of the table - if the value in row i and column B equals 0 i would like to delete the entire row.
this is the code i wrote but nothing happens when i run it
Sub deleteZeroRows()
'loop for deleting zero rows
Dim wbCurrent As Workbook
Dim wsCurrent As Worksheet
Dim nLastCol, i As Integer
Set wbCurrent = ActiveWorkbook
Set wsCurrent = wbCurrent.ActiveSheet
Dim lastRow As Long
lastRow = Range("b2").End(xlDown).Select
For i = 2 To lastRow
If wsCurrent.Cells(i, 2) = 0 Then
wsCurrent.Cells(i, 2).EntireRow.Delete
End If
Next i
End Sub
A faster method to delete multiple rows from your worksheet is to store all the Rows that need to be deleted in a Range, using the Union function.
After you exit your For loop, just delete the entire rows DelRng at one command.
More notes in my code's comments below.
Code
Option Explicit '<-- always use this at the top of your code
Sub deleteZeroRows()
Dim wbCurrent As Workbook
Dim wsCurrent As Worksheet
Dim lastRow As Long, nLastCol As Long, i As Long
Dim DelRng As Range
Set wbCurrent = ActiveWorkbook '<-- try to avoid using Active...
Set wsCurrent = wbCurrent.ActiveSheet '<-- try to avoid using Active...
With wsCurrent
lastRow = .Cells(.Rows.Count, "B").End(xlUp).Row ' get last row in column B
For i = 2 To lastRow
If .Range("B" & i).Value = 0 Then
If Not DelRng Is Nothing Then
' add another row to DelRng range
Set DelRng = Application.Union(DelRng, .Rows(i))
Else
Set DelRng = .Rows(i)
End If
End If
Next i
End With
' if there's at least 1 row to be deleted >> delete all rows in DelRng at 1-line
If Not DelRng Is Nothing Then DelRng.Delete
End Sub
a "fast & furious" code:
Sub deleteZeroRows()
With Range("B2", Cells(Rows.Count, 2).End(xlUp)) 'reference column B cells from row 2 down to last not empty one
.Replace what:=0, lookat:=xlWhole, replacement:="" ' replace 0's with blanks
If WorksheetFunction.CountBlank(.Cells) > 0 Then .SpecialCells(XlCellType.xlCellTypeBlanks).EntireRow.Delete ' delete rows where referenced range is blank
End With
End Sub
which will also delete rows whose column B content is blank

Match, Copy, and Add Values between Sheets

Looking to match values of column 1&2 of the same row on sheet2 to values of column 1&2 of the same row on sheet1. Then, copy entire row of sheet1 match onto next blank row of sheet3 + copy value of column 3+4 of same row sheet2 onto end of pasted row on sheet3.
IF Sheet2 Row First&Last (column1&2) Name match Sheet1 Row First&Last (column1&2)
THEN
Copy Sheet1 Row, paste to Sheet3 # next blank Row. Copy Sheet2 Row column 3+4 # end of previously pasted Row on Sheet3
Here is what I have so far, this doesn’t do anything right now but I have pieced it together from a few working macros to try and accomplish what I’m after. I haven’t been able to find examples of “Copy Sheet2 Row column 3+4 # end of previously pasted Row on Sheet3” so I just have a description on the line where I think the code should go.
Sub Match_Copy_AddValues()
Dim s1 As Worksheet, s2 As Worksheet, s3 As Worksheet
Application.ScreenUpdating = False
Application.EnableEvents = False
Set s1 = ActiveSheet 'List with dump data'
Set s2 = Sheets("Sheet 2") 'List of names to match, and additional information to be added'
Set s3 = Sheets("Sheet 3") 'Worksheet to copy rows of matched names'
Dim r As Long 'Current Row being matched?'
On Error GoTo fìn
Set ws2 = Sheets("Sheet 2")
With Sheets("Sheet 1")
r = Application.Max(.Cells(Rows.Count, 1).End(xlUp).Row, .Cells(Rows.Count, 2).End(xlUp).Row) 'Defines # of rows to apply If/Then to?'
For r = Application.Sum(v) To 2 Step -1 'Each time If/Then is ran, reduce # of rows to apply If/Then to?'
If CBool(Application.CountIfs(ws2.Columns(1), .Cells(r, 1).Value, ws2.Columns(2), .Cells(r, 2).Value)) Then _
.Rows(r).EntireRow.Copy s3.Cells(K, 1) 'Compares value in (r)row column 1 and 2, sheet2, to sheet1(activesheet), if equal THEN copies entire (r)row onto sheet3 # next empty row'
'take (r)row of match and copy value of column 3 and 4 sheet2 onto the end of previously pasted row on sheet3'
Next r
End With
fìn:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
The code below doesn't do everything just the way your attempt suggests but I wrote it in very plain language so that you will surely be able to teak it back into your track where it has transgressed to where it shouldn't go.
Sub MatchNameAndInfo()
' 02 Aug 2017
Dim WsInput As Worksheet
Dim WsInfo As Worksheet
Dim WsOutput As Worksheet
Dim Rl As Long ' Last row of WsInput
Dim R As Long ' WsInput/WsInfo row counter
Dim Tmp1 As String, Tmp2 As String ' Clm 1 and Clm2 Input values
Dim Cmp1 As String, Cmp2 As String ' Clm 1 and Clm2 Info values
Set WsInput = Worksheets("Krang (Input)")
Set WsInfo = Worksheets("Krang (Info)")
Set WsOutput = Worksheets("Krang (Output)")
Application.ScreenUpdating = False
With WsInput
Rl = Application.Max(.Cells(.Rows.Count, 1).End(xlUp).Row, _
.Cells(.Rows.Count, 2).End(xlUp).Row)
If Rl < 2 Then Exit Sub
For R = 2 To Rl ' define each input row in turn
Tmp1 = Trim(.Cells(R, 1).Value)
Tmp2 = Trim(.Cells(R, 2).Value)
Cmp1 = Trim(WsInfo.Cells(R, 1).Value)
Cmp2 = Trim(WsInfo.Cells(R, 2).Value)
If StrComp(Tmp1 & Tmp2, Cmp1 & Cmp2, vbTextCompare) = 0 Then
TransferData R, WsInfo, WsOutput
End If
Next R
End With
Application.ScreenUpdating = True
End Sub
Private Function TransferData(R As Long, _
WsInfo As Worksheet, _
WsOut As Worksheet)
' 02 Aug 2017
Dim Rng As Range
Dim Rt As Long ' target row
With WsInfo
Set Rng = .Range(.Cells(R, 1), .Cells(R, 4))
End With
With WsOut
Rt = Application.Max(.Cells(.Rows.Count, 1).End(xlUp).Row + 1, 2)
Rng.Copy Destination:=.Cells(Rt, 1)
End With
End Function

Split data by empty row and rename the new sheets by cell value from the original data set

I have the following data set in Sheet1 with headings as you see below:
I want to split the big data set into different sheets by every empty row. Every data set is separated by an empty row, and every data set have values in all cells in columns A and E but their columns B, C, D might have some empty cells randomly. So the defining element to split is the empty rows in column E.
Q1: I want to copy the headings A1:D1 to the new sheets and only copy the columns A:D and not the column E.
Q2: I want to rename new sheets to take the cell value in column E as their name.
So the *results are the following:
Sheet ID1:
Sheet ID2:
Sheet ID3:
I have tried the following code, it works, but it only copies the first table, without renaming the sheet to take the cell value in column E, and it should copy the column E so it should copy only A:D, and it doesn't loop through all tables.
Sub Split_Sheets_by_row()
Dim lLoop As Long, lLoopStop As Long
Dim rMove As Range, wsNew As Worksheet
Set rMove = ActiveSheet.UsedRange.Columns("A:E")
lLoopStop = WorksheetFunction.CountIf(rMove, "Heading5")
For lLoop = 1 To lLoopStop
Set wsNew = Sheets.Add
rMove.Find("Heading5", rMove.Cells(1, 1), xlValues, _
xlPart, , xlNext, False).CurrentRegion.Copy _
Destination:=wsNew.Cells(1, 1)
Next lLoop
End Sub
Your help is very much appreciated.
I've taken a slightly different approach but I have achieved the results you are looking for.
Sub Split_Sheets_by_row()
Dim hdr As Range, rng As Range, ws As Worksheet, wsn As Worksheet
Dim rw As Long, lr As Long, b As Long, blks As Long
Set ws = ActiveSheet
With ws
Set hdr = .Cells(1, 1).Resize(1, 4)
lr = .Cells(Rows.Count, 5).End(xlUp).Row
rw = 2
blks = Application.CountBlank(.Range(.Cells(rw, 1), .Cells(lr, 1))) + 1
For b = 1 To blks
Set rng = .Cells(rw, 1).CurrentRegion
Set rng = rng.Offset(-CBool(b = 1), 0).Resize(rng.Rows.Count + CBool(b = 1), 4)
Set wsn = Worksheets.Add(after:=Sheets(Sheets.Count))
With wsn
.Name = rng.Offset(0, 4).Cells(1, 1).Value
hdr.Copy Destination:=.Cells(1, 1)
rng.Copy Destination:=.Cells(2, 1)
End With
rw = rw + rng.Rows.Count + 1
Set rng = Nothing
Set wsn = Nothing
If rw > lr Then Exit For
Next b
End With
Set rng = Nothing
Set ws = Nothing
End Sub
The header is stored for repeated use and the number of blocks of data are counted by counting the separating blank rows and adding 1. The value from column E is used to rename the worksheet but is not carried across in the data transfer to the new worksheet.
I'm not sure how you would want to handle a worksheet with the same name already existing but they could be deleted before a new worksheet is renamed.