Match cells in two sheets and copy paste the match content - excel

I'm totally new to the vba. I have two excel sheets, and I'm trying to compare and match the cells in one of the columns in two sheets. If matched cells are found, information of the adjacent cells will be copied and paste to another sheet(sheet1).
I have a code that works just fine but incomplete. Because there are repetitive cells in a column, the code once finds a match and copy-paste the info, it skips to the next non-repeated cells. Thus resulting in a lot of blank, missing cell. Any idea to make it fill in the blank?
Image:
Sheet2:
Sub Button2_Click()
Dim lastRw1, lastRw2, nxtRw, m
lastRw1 = Sheets(1).Range("A" & Rows.Count).End(xlUp).Row
lastRw2 = Sheets(2).Range("B" & Rows.Count).End(xlUp).Row
'Loop
For nxtRw = 2 To lastRw2
'Search
With Sheets(1).Range("A2:A" & lastRw1)
Set m = .Find(Sheets(2).Range("B" & nxtRw), LookIn:=xlValues, lookat:=xlWhole)
'Copy
If Not m Is Nothing Then
Sheets(2).Range("C" & nxtRw & ":D" & nxtRw).Copy _
Destination:=Sheets(1).Range("J" & m.Row)
End If
End With
Next
End Sub

Updated:
I took a small sample of your Sheet2 data set:
I also updated your code as follows (main change - I replaced Find with Match in order to find the matching row number):
Dim lastRw1 As Long, lastRw2 As Long, nxtRw As Long, m As Long
lastRw1 = Sheets(1).Range("A" & Rows.Count).End(xlUp).Row
lastRw2 = Sheets(2).Range("B" & Rows.Count).End(xlUp).Row
'Loop
For nxtRw = 2 To lastRw1
'Search
With Sheets(1)
m = Application.Match(.Range("A" & nxtRw).Value, _
Sheets(2).Range("B1:B" & lastRw2), 0)
'Copy
If m Then
Sheets(2).Range("C" & m & ":D" & m).Copy _
Destination:=.Range("J" & nxtRw)
End If
End With
Next
Final result:

Related

for loop over sheets in a workbook with formulas until the end of a column with data

I have have the following problem with vba and would like to ask you for help.
I hope I haven't overseen a similar question in the froum
I have several sheets in an excel workbook. On each sheet I would like to run the same formulas. The formula gets its data from the cell C3 on the same sheet and should run until the end of the data in column C xxx . The length of the data is different on each sheet. Each sheet has its own data set.
The code I have written works fine in the sense that it works itself through through the sheets starting from sheet 2 until the end of the sheets.
The code gets executed via an icon in the toolbar.
On each sheet I have values what the formulas should use. The values in column C are different long. Some have for example just 15 some have over 300000.
For example, if I press the icon when I'm on sheet 1 with no data in column C the macro takes the first 15 values/range of the column for the formulas in all sheets. Which means I miss all values from for example at sheet 3 with 300000 values. If I am on sheet 3 and press the icon there I takes the 300000 values/range and uses the range of the 300000 values in all the other sheets.
If I run the code without the loop on each sheet it works fine. It selects the right range with values of the column.
There are no empty cells in the column.
Has anyone an idea what is wrong in the code that it does not select the real amount of values in column C for the different sheets?
I work on a mac with excel 14.
The following code is what I have so far:
Sub Start()
Dim i As Long
lastrow = Cells(Rows.Count, 3).End(xlUp).Row
For i = 2 To Worksheets.Count
With Sheets(i)
.Range("K11").Formula = "=COUNT(C3:C" & lastrow & ")"
.Range("K12").Formula = "=MEDIAN(C3:C" & lastrow & ")"
.Range("K13").Formula = "=AVERAGE(C3:C" & lastrow & ")"
.Range("K14").Formula = "=MIN(C3:C" & lastrow & ")"
.Range("K15").Formula = "=MAX(C3:C" & lastrow & ")"
.Range("K16").Formula = "=STDEVP(C3:C" & lastrow & ")"
End With
Next i
End Sub
You have to use .Cells to make it refer to the object in the With statement, otherwise it refers to the current sheet:
Sub Start()
Dim i As Long
For i = 2 To Worksheets.Count
With Sheets(i)
lastrow = .Cells(Rows.Count, 3).End(xlUp).Row
Debug.Print (i)
Debug.Print (lastrow)
.Range("K11").Formula = "=COUNT(C3:C" & lastrow & ")"
.Range("K12").Formula = "=MEDIAN(C3:C" & lastrow & ")"
.Range("K13").Formula = "=AVERAGE(C3:C" & lastrow & ")"
.Range("K14").Formula = "=MIN(C3:C" & lastrow & ")"
.Range("K15").Formula = "=MAX(C3:C" & lastrow & ")"
.Range("K16").Formula = "=STDEVP(C3:C" & lastrow & ")"
End With
Next i
End Sub

VBA, Fill up/down rows to align with last row

I am trying to delete rows till it meets my last row OR fill down rows to align with last row.
Sometimes my sheet will be like below where I need to delete rows to align with my last row number.:
However sometimes my sheet will be like below, where I need to fill down other columns:
Is there a function that can do this? I am finding it hard to determine when to fill up or fill down.
Thanks
keeping in mind the well known caveats of the use of UsedRange, you could give it a try
Dim lastRow As Long
With ActiveSheet ' <- change it to your actual sheet reference
With .UsedRange
lastRow = .Rows(.Rows.Count)
End With
End With
Please test the next code. It assumes that the reference column will be the seventh one and the one to check the 0 formulas value to be the sixth one. Your picture does not contain the columns header...
Sub DeleteRowsOrFillDownDiscontinuous()
Dim sh As Worksheet, lastR As Long, lastR1 As Long, lastCol As Long
Set sh = ActiveSheet
lastR = sh.Range("F" & rows.count).End(xlUp).row
lastR1 = Range("E" & rows.count).End(xlUp).row
lastCol = sh.cells(lastR1, Columns.count).End(xlToLeft).Column
If lastR < lastR1 Then
sh.rows(lastR + 1 & ":" & lastR1).EntireRow.Delete xlUp
ElseIf lastR > lastR1 Then
sh.Range("A" & lastR1, "E" & lastR1).AutoFill _
Destination:=sh.Range("A" & lastR1, sh.Range("E" & lastR))
sh.Range("G" & lastR1, "AG" & lastR1).AutoFill _
Destination:=sh.Range("G" & lastR1, "AG" & lastR)
sh.Range("AI" & lastR1, sh.cells(lastR1, lastCol)).AutoFill _
Destination:=sh.Range("AI" & lastR1, sh.cells(lastR, lastCol))
Else
MsgBox "Nothing te be processed. Everything aligned..."
End If
End Sub
Edited:
Adapted the code for F:F column as reference, AH:AH not changeable, too and existing columns to be processed after AH Column.
Please test it and send some feedback.

Excel VBA is Finding Every Other Cell not Every Cell From Method

Excel VBA is finding every other cell using a method to check for Empty Cells. On the next time running the same macro, it then finds the cell that it skipped over on the last run while again skipping the next instance of an empty cell. If I cycle through the macro a few times, eventually every row without data is getting deleted, as per the purpose of the macro. The rows do shift upward upon deletion of the row one at a time, I will try a Union and delete the Range as stated by #BigBen
When a cell that is empty is found, it checks columns A, B, and D to see if formula is applied, and if a formula exists in that row, the entire row gets deleted.
Dim cel, dataCells As Range
Dim rngBlank, dc As Range
Dim lastRow, cForm, c, blnkRange As String
Dim cycleTimes As Integer
On Error Resume Next
Set dataCells = Range("F2:W2").Cells 'This is header of the table of data
cycleTimes = dataCells.Count 'Number of times to cycle through macro
For Count = 1 To cycleTimes 'I don't want to cycle through macro
lastRow = Range("N" & Rows.Count).End(xlUp).Row 'To find end of column
For Each dc In dataCells
c = Split(Cells(1, dc.Column).Address, "$")(1) 'Column Letter
blnkRange = c & "3:" & c & lastRow 'Range to look over for empty cells
Set rngBlank = Range(blnkRange).SpecialCells(xlCellTypeBlanks).Cells
For Each cel In rngBlank '**Skipping Every other Row**
If Not TypeName(cel) = "Empty" Then
cForm = "A" & cel.Row & ",B" & cel.Row & ",D" & cel.Row 'Formula check
If Range(cForm).HasFormula Then
cel.EntireRow.Delete
End If
End If
Next
Next
Next
I was able to use Intersect to find the rows that matched the criteria I was searching for and delete the EntireRow even though the Selection was in separate Rows.
Set dataCells = Range("F2:W2").Cells
lastRow = Range("N" & Rows.Count).End(xlUp).Row 'To find last row to generate range to look through
For Each dc In dataCells 'Have to perform delete row for every column
c = Split(Cells(1, dc.Column).Address, "$")(1)
blnkRange = c & "3:" & c & lastRow
Set rngBlank = Range(blnkRange).SpecialCells(xlCellTypeBlanks).EntireRow
strFormula = "A2:A" & lastRow & ",B2:B" & lastRow & ",C2:C" & lastRow
Set rngFormula = Range(strFormula).SpecialCells(xlCellTypeFormulas)
Intersect(rngFormula, rngBlank).EntireRow.Delete (xlShiftUp) '**THIS helped in deleting Rows**
Next

Copy/Paste last two rows into next empty row and clear certain cells (contains merged cells)

I'm trying to make a command button up the top of my sheet which when pressed will copy the last 2 rows in columns A:AJ that have data and paste into the next empty row below them. I want the source style and formulas to be copied but not the manually entered data. I have an image here too to help:
So for example from the image. I want to copy rows 105/106 together and then paste them to 107/108 as they are the next empty rows(although hidden so would also need to unhide those rows).
Everything in those 2 rows should be copied except the bottom "strokes" section and par/strokes box is a formula/date/data validation/dropdown which I want copied but the strokes section to be empty as well as date/dropdown be blank too. I would like it to all look the same as well (copy the style). Filled cells to clear in that scenario would be column B, C, E:M, P:X but only on the "STROKES" row.
To put it even more basically. I want a button to push that will add another row to the table. So I have 52 there in the picture you can see, when pressed I will now have 53 below it and it be blank ready for use.
If the hidden rows need to be unhidden for this to work I can do that.
I have looked to try do it myself but I've never done anything with VBA before so I have no idea.
I hope someone can understand this request and that it is even doable.
Thanks.
Based on DecimalTurn's answer, I made some changes and here's my new code:
Private Sub CommandButton1_Click()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear1() As Variant
Dim ListOfColumnsToClear2() As Variant
ListOfColumnsToClear1 = Array("B:C")
ListOfColumnsToClear2 = Array("E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear1) To UBound(ListOfColumnsToClear1)
Intersect(ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear1(i))).ClearContents
Next i
For i = LBound(ListOfColumnsToClear2) To UBound(ListOfColumnsToClear2)
Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear2(i))).ClearContents
Next i
End Sub
It's probably completely wrong but it did work.
To achieve what you are trying to do with VBA, I would suggest to have your code do the following (in that order):
Find the last row of data.
Define the range to copy and copy that range.
Ajust line numbering
Clear the content of the cells that need manual inputs.
Assuming you don't need to unhide any rows, the code would look like this:
Sub CopyLastTwoRows()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear() As Variant
ListOfColumnsToClear = Array("B:C", "E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear) To UBound(ListOfColumnsToClear)
Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear(i))).ClearContents
Next i
End Sub
Now, since you have merged cells, the section where we clear data will give you an error since only the bottom part of your merged cells will intersect. To solve this, we can use a function that will make sure that if there are merged cells in our range, all their cells will be included.
The code would look like this (note the new function at the end):
Sub CopyLastTwoRows()
'Find the last row based on column D (4th)
Dim LastRow As Long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 4).End(xlUp).Row
'Copy the range
ActiveSheet.Range("A" & (LastRow - 1) & ":" & "AJ" & LastRow).Copy
ActiveSheet.Range("A" & (LastRow + 1) & ":" & "AJ" & LastRow + 2).PasteSpecial
Application.CutCopyMode = False 'This will clear the clipboard
'Adjust numbering
ActiveSheet.Range("A" & LastRow + 1).Value2 = ActiveSheet.Range("A" & LastRow - 1).Value2 + 1
'Clear content
Dim ListOfColumnsToClear() As Variant
ListOfColumnsToClear = Array("B:C", "E:M", "P:X")
Dim i As Long
For i = LBound(ListOfColumnsToClear) To UBound(ListOfColumnsToClear)
ExpandToIncludeMergedCells(Intersect(ActiveSheet.Range("A" & (LastRow + 2) & ":" & "AJ" & LastRow + 2), ActiveSheet.Range(ListOfColumnsToClear(i)))).ClearContents
Next i
End Sub
Private Function ExpandToIncludeMergedCells(ByRef Rng As Range) As Range
Dim TempRange As Range
Set TempRange = Rng.Cells(1)
Dim c As Range
For Each c In Rng
Set TempRange = Union(TempRange, c.MergeArea)
Next c
Set ExpandToIncludeMergedCells = TempRange
End Function
Finally, if you want to do this multiple times (say 10 times) by pressing a button, you would simply do:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim i As Long
For i = 1 To 10
CopyLastTwoRows
Next i
Application.ScreenUpdating = True
End Sub
Note that I'm using Application.ScreenUpdating = False to tell Excel not to refresh the screen while the macro is running. This will make your code run much faster, but it's recommended to set it back to true at the end and to have some error handling (which I didn't include here).

Copy row of data based on criteria AND "label" that copied data in last column

I have working code that checks for a criteria in each row, and if met, copies that whole row of data over to a different workbook. But! I need to be able to add text to the last column of the copied data (Column S) that essentially labels what criteria was met that made the code copy it over because I will soon be expanding to check for multiple different criteria.
So for every row that meets the criteria and gets copied, I want to add "Criteria1" next to it in column S in the new workbook (it will always be column S that will be the first available column).
I have mangled this code together through inheritance and all of your help, so I don't really even know where to begin.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim CoderBook As Workbook
Dim Referrals As Worksheet
Dim Review As Workbook
Dim Crit As Worksheet
Dim LastRow As Long
Dim NextRow As Long
Dim i As Long
Set CoderBook = Workbooks.Open("Coder Referrals.xlsx")
Set Referrals = CoderBook.Sheets("Sheet1")
Set Review = ThisWorkbook
Set Crit = Review.Sheets("Criteria")
'Search code
LastRow = Crit.Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Application.ScreenUpdating = False
'Loop search code
For i = 2 To LastRow
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Or _
Crit.Range("I" & i) <> Crit.Range("J" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = Crit.Rows(i).Value
End If
Next i
'End loop code
CoderBook.Close SaveChanges:=True
Application.ScreenUpdating = True
End Sub
Split the or into two statements:
For i = 2 To LastRow
j = Referrals.Cells(Rows.Count, 1).End(xlUp).row + 1
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
Referrals.Range("S" & j).Value = "Criteria1"
End If
If Crit.Range("I" & i) <> Crit.Range("J" & i) Then
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
if Referrals.Range("S" & j).value = vbNullString then
Referrals.Range("S" & j).Value = "Criteria2"
Else
Referrals.Range("S" & j).Value = Referrals.Range("S" & j).Value & ", " & "Criteria2"
End if
Next i

Resources