The For Each...Next
loop doesn't automatically keep track of which rows you have deleted. When you delete a row, Cell
still points to the same address (which is now the row below the original one, since that was deleted). Then on the next time round the loop, Cell
moves onto the next cell, skipping one.
To fix this, you could move Cell
up one within the If
statement (e.g. with Set Cell = Cell.Offset(-1,0)
). But I think this is one of the rare cases where a simple For
loop is better than For Each
:
Dim lngLastRow As Long
Dim lngSourceRow As Long
Dim lngDestRow As Long
Dim objSourceWS As Worksheet
Dim objDestWS As Worksheet
Set objSourceWS = ActiveWorkbook.Sheets(1)
Set objDestWS = ActiveWorkbook.Sheets(2)
lngLastRow = objSourceWS.Range("C" & objSourceWS.Rows.Count).End(xlUp).Row
lngDestRow = 1
For lngSourceRow = lngLastRow To 1 Step -1
If objSourceWS.Cells(lngSourceRow, 3).Value = "CHOFF" Then
objSourceWS.Rows(lngSourceRow).Copy Destination:=objDestWS.Cells(lngDestRow, 1)
objSourceWS.Rows(lngSourceRow).Delete
lngDestRow = lngDestRow + 1
End If
Next lngSourceRow
This loops backwards (as per Portland Runner's suggestion) to avoid having to do anything about deleted rows. It also tidies up a couple of other things in your code:
- You don't need to do any
Select
ing, and it's better not to (see this question for why)
- You can specify a destination within
Range.Copy
rather than having to do a separate select and paste
- You can change the value of a variable "in place" without having to assign it to a second variable first (i.e.
x = x + 1
is fine)
- you should use
Long
rather than Integer
for variables that contain row numbers, since there are more rows in an Excel spreadsheet than an Integer
can handle (at least 65536 compared to 32767 max for an Integer
)
Obviously test that it still does what you require!