My data looks like this.
I would like to delete rows where the value in column named Position from first has value 1. I wrote a macro to do that which is like this
Sub DEL_row()
row_number = 2
Do
DoEvents
row_number = row_number + 1
Position_from_first = Sheet8.Range("E" & row_number)
If InStr(Position_from_first, "1") >= 1 Then
Sheet8.Rows(row_number & ":" & row_number).Delete
End If
Loop Until Position_from_first = ""
MsgBox "completed"
End Sub
But when i run it, I get an error. The msg box says completed but it does not do the required job when I go through the excel sheet.
Can anyone help me what the problem would be.
Thanks a lot for helping...
While your concept is spot on, there are some errors in your syntax and your understanding of VBA. I have listed them below.
No need for Do Events in this code at all.
When deleting rows, you need to start from the last row and step back to the beginning in your looping because as you soon as you delete a row it affects all the row references below that, so your loop count will miss rows if you go forward.
You also need to use .EntireRow.Delete. .Delete will only delete cell content.
I have fixed your code below to reflect these issues. I have also provided a simpler alternative to solve your problem below that which uses the AutoFilter method.
Sub DEL_row()
'get last used row in column E
row_number = Sheet8.Range("E" & Sheet8.Rows.Count).End(xlup).Row
For x = row_number to 2 Step -1
Position_from_first = Sheet8.Range("E" & row_number)
If InStr(Position_from_first, "1") >= 1 Then
'If Sheet8.Range("E" & row_number) = 1 ' this will also work
Sheet8.Rows(row_number & ":" & row_number).EntireRow.Delete
End If
Next
MsgBox "completed"
End Sub
You can avoid the loop altogether (and save time) if you use AutoFilter, like this:
Sub DEL_row()
With Sheet8
'get last used row in column E
row_number = .Range("E" & .Rows.Count).End(xlup).Row
With .Range("E1:E" & row_number)
.AutoFilter 1, "1"
.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
End With
Msgbox "completed"
End Sub
I gather that you do not want to delete 11, 12, 31, ... etc. so using the InStr function is not an appropriate method of identifying the correct rows to delete. Your sample data image shows column E as having true, right-aligned numbers and the Range.Value2 property can be directly compared against a 1 to determine if the row should be removed.
As mentioned, working from the bottom to the top is important when deleting rows. If you work from the top to the bottom you risk skipping a row when a row has been deleted, everything shifts up and then you increment to the next row.
Option Explicit
Sub DEL_1_rows()
'declare your variables
Dim rw As Long
'this will greatly improve the speed involving row deletion
Application.ScreenUpdating = False
With sheet8 '<~~ this is a worksheet CodeName - see below
For rw = .Cells(Rows.Count, 5).End(xlUp).Row To 2 Step -1
If .Cells(rw, 5).Value2 = 1 Then .Rows(rw).EntireRow.Delete
Next rw
End With
Application.ScreenUpdating = True
MsgBox "completed"
End Sub
An AutoFilter Method can speed up identifying the rows to delete. However, a single large bulk deletion can still take a significant amount of processing time.
Option Explicit
Sub DEL_Filtered_rows()
'this will greatly improve the speed involving row deletion
Application.ScreenUpdating = False
With Sheet8 '<~~ this is a worksheet CodeName - see below
If .AutoFilterMode Then .AutoFilterMode = False
With .Range(.Cells(1, 5), .Cells(Rows.Count, 5).End(xlUp))
.AutoFilter field:=1, Criteria1:=1
With .Resize(.Rows.Count, .Columns.Count).Offset(1, 0)
If CBool(Application.Subtotal(103, .Cells)) Then
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End If
End With
.AutoFilter
End With
End With
Application.ScreenUpdating = True
MsgBox "completed"
End Sub
I found it a little odd that you were identifying the worksheet with a Worksheet .CodeName property rather than a Worksheet .Name property. I've included a couple of links to make sure you are using the naming conventions correctly. In any event, I've use a With ... End With statement to avoid repeatedly reidentifying the parent worksheet.
Related
This is currently the setup that I have found helpful and have modified to work well... However, I'm struggling with one small further and final modification. I would like to just - Paste Values as opposed to the Formulas.
Sub move_rows_to_another_sheet()
'
Sheets("User").Select
Columns("A:Y").Select
Range("A:Y").Activate
'
For Each myCell In Selection.Columns(25).Cells
If myCell.Value = "Closed" Then
myCell.EntireRow.Copy Worksheets("Archive").Range("A" & Rows.Count).End(3)(2)
myCell.EntireRow.Delete
End If
Next
'
Range("A2").Select
End Sub
''Updated Version - Move Single Rows
'
Sub move_rows_to_another_sheet()
'
Sheets("Users").Select
Columns("A:Y").Select
Range("A:Y").Activate
'
For Each mycell In Selection.Columns(25).Cells
'
If mycell.Value = "Closed" Then
mycell.EntireRow.Copy
Worksheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValuesAndNumberFormats
mycell.EntireRow.Delete
End If
Next
'
Range("A2").Select
End Sub
The idea is simple... The current code is successful, however, I would like to just copy and paste the [values] of the rows cell content and [not] the formulas etc. The formatting is fine and everything, I just need the result of the functioning formulas recorded.
I have tried various options such as [myCell.EntireRow.CopyValues] even [& Rows.Count & Rows.PasteSpecial]... Any thoughts?
Thanks in advance
I tried your code. It looks like when there are several cells with "closed" it will not work for all. because when one deletes, one should delete from below upwards.
But then the data in Archive is not in right order.
In your original code you can make the range smaller, so it will run faster.
or take what you want from this code:
Sub move_rows_to_another_sheet2()
Dim mycell As Range
Dim checkClosed
Dim Lastrow As Long
Dim i As Long
Set checkClosed = ThisWorkbook.Worksheets("User").Range("Y1:Y10000")
Lastrow = Worksheets("Archive").Cells(Rows.Count, 1).End(xlUp).Row + 1 'one cell below last used cell in column A
For i = 10000 To 1 Step -1 'from row 10000 to row 1
Set mycell = ThisWorkbook.Worksheets("User").Cells(i, "Y")
If LCase(mycell.Value) = "closed" Then 'checks for Closed and closed
mycell.EntireRow.Copy
Worksheets("Archive").Range("A" & Lastrow).PasteSpecial Paste:=xlPasteValues
mycell.EntireRow.Delete
Lastrow = Lastrow + 1
End If
Next i
'
Range("A2").Select
End Sub
I am trying to copy filtered data from one sheet to another, but for some reason I get a runtime error 1004 saying "to copy all cells from another worksheet to this worksheet make sure you paste them into the first cell (A1 or R1C1)" I actually don't want the header row copied, so all visible bar that row
What I am wanting is the copied data to be pasted to the first available row in the target sheet. Here is the code I have which filters for certain things, but then falls over on the paste line
Sub BBWin()
'
' BB Win Macro
' This macro will filter BB Win 1 - 8
'
With ActiveSheet.Range("A1").CurrentRegion
With .Resize(, .Columns.Count + 1)
With .Cells(2, .Columns.Count).Resize(.Rows.Count - 1)
.FormulaR1C1 = "=if(or(rc7={""K.BB_Win_1_2019"",""K.BB_Win_2_2019"",""K.BB_Win_3_2019"",""K.BB_Win_4_2019"",""K.BB_Win_5_2019"",""K.BB_Win_6_2019"",""K.BB_Win_7_2019"",""K.BB_Win_8_2019""}),""X"","""")"
.Value = .Value
End With
.HorizontalAlignment = xlCenter
End With
Cells.Select
Selection.SpecialCells(xlCellTypeVisible).Copy
Workbooks("Predictology-Reports.xlsx").Sheets("BB Reports").Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
End With
Application.CutCopyMode = False
End Sub
Any suggestions as to what is missing to have it work correctly?
=========================================
OK, perhaps I should have tried the question another way, posting the original working macro I was supplied, rather than posting my attempt to rewrite it.
This is basically the same thing as what I posted above, with the formula changed to look for different text, though it also has autofilter settings (which I don't need) and hides columns (which I don't need to do). This is working perfectly for me and does exactly what it is supposed to. I basically tried to duplicate it and remove the unwanted elements, but as you saw, found the error originally indicated. Obviously my limited knowledge caused the initial issue.
Sub Low_Risk()
'
' Low Risk Lays Macro
' This macro will filter for Remove VDW Rank 1, Class, Distance <=1650, # of Runners <=9, Exclude Brighton, Yarmouth, Windsor & Wolverhampton
'
With ActiveSheet.Range("A1").CurrentRegion
With .Resize(, .Columns.Count + 1)
With .Cells(2, .Columns.Count).Resize(.Rows.Count - 1)
.FormulaR1C1 = "=if(or(rc8={""Brighton"",""Yarmouth"",""Windsor"",""Wolverhampton""}),""X"","""")"
.Value = .Value
End With
.AutoFilter Field:=4, Criteria1:="<=9"
.AutoFilter Field:=11, Criteria1:="<=1650"
.AutoFilter .Columns.Count, "<>X"
.AutoFilter Field:=29, Criteria1:="<>1"
.HorizontalAlignment = xlCenter
End With
.Columns("C:C").EntireColumn.Hidden = True
.Columns("G:G").EntireColumn.Hidden = True
.Columns("I:I").EntireColumn.Hidden = True
.Columns("L:L").EntireColumn.Hidden = True
.Columns("N:W").EntireColumn.Hidden = True
.Columns("Y:AB").EntireColumn.Hidden = True
.Columns("AD:AJ").EntireColumn.Hidden = True
.Columns("AO:AO").EntireColumn.Hidden = True
.Columns("AQ:BQ").EntireColumn.Hidden = True
.Columns("BT:CP").EntireColumn.Hidden = True
.Parent.AutoFilter.Range.Offset(1).Copy
Workbooks("New Results File.xlsm").Sheets("Low Risk Lays").Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
End With
Application.CutCopyMode = False
End Sub
As indicated, this works absolutely perfectly, nested Withs and all. I can change the original formula so it is looking in the correct column and only for the text I want, but I obviously was not able to successfully remove the autofilter elements and the elements which hide columns without bringing up an error. I assume the removal of the .Parent.AutoFilter.Range.Offset(1).Copy line was the culprit, but wasn't sure how to approach the removal of the unwanted elements.
This original macro was supplied to me in one of the forums and I am loath to alter the formula part which does a good job of looking for the many text elements required to be copied. That was why I only looked to alter the autofilter section and hidden column section
I'm not sure if this helps at all, but it may clarify things a little
cheers and thanks so much for your effort
Cells.Select (with no leading period to tie it to the With block) will select all cells on whatever is the active sheet.
Try this (nested With's confuse me a bit, so removed a couple)
Sub BBWin()
Dim arr, ws As Worksheet, lc As Long, lr As Long
arr = Array("K.BB_Win_1_2019", "K.BB_Win_2_2019", "K.BB_Win_3_2019", _
"K.BB_Win_4_2019", "K.BB_Win_5_2019", "K.BB_Win_6_2019", _
"K.BB_Win_7_2019", "K.BB_Win_8_2019")
Set ws = ActiveSheet
'range from A1 to last column header and last row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lr = ws.Cells.Find("*", after:=ws.Range("A1"), LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
With ws.Range("A1", ws.Cells(lr, lc))
.HorizontalAlignment = xlCenter
.AutoFilter Field:=7, Criteria1:=arr, Operator:=xlFilterValues
.Offset(1, 0).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy
End With
Workbooks("Predictology-Reports.xlsx").Sheets("BB Reports") _
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
Application.CutCopyMode = False
End Sub
Cells.Select selects all sheets cells.
Selection.SpecialCells(xlCellTypeVisible) keeps all cells, since nothing is hidden and everything is visible. You said something about "copy filtered data" but your code does not filter anything...
So, there is not place to paste all cells.
In order to make your code working, replace Cells.Select with .Cells.Select (the dot in front makes it referring to the resized UsedRange). Even if any selection is not necessary...
So, (better) use .cells.SpecialCells(xlCellTypeVisible).Copy...
Edited:
Your last code needs to only copy the visible cells of the filtered range. So, your code line
.Parent.AutoFilter.Range.Offset(1).Copy
must be replaced by the next one:
.Parent.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Copy
or
.Offset(1).SpecialCells(xlCellTypeVisible).Copy
which refers the processed range (`UsedRange'), starting from the second row.
What I am wanting is the copied data to be pasted to the first
available row in the target sheet.
You should define your available row to paste your fillered rows in, or first blank row in the sheet you want the filtered data pasted. Then you will be able to paste your data into that row.
In my example, I'm filtering my datawork (source sheet) sheet by anything in col 24 that contains "P24128" and pasting into "Sheet8" (Target sheet), in my example.
I actually don't want the header row copied, so all visible bar that
row
You also didnt want the headers. :)
Sub CopyFilteredDataSelection10()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Datawork")
ws.Activate
'Clear any existing filters
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0
'1. Apply Filter
ActiveSheet.Range("A1:ADU5000").AutoFilter Field:=24, Criteria1:="*P24128*" ' "*" & "P24128" & "*" ' im filtering by anything in col 24 that contains "P24128"
'2. Copy Rows minus the header
Application.DisplayAlerts = False
ws.AutoFilter.Range.Copy 'copy the AF first
Set Rng = ws.UsedRange.Offset(1, 0)
Set Rng = Rng.Resize(Rng.Rows.Count - 1)
Rng.Copy
'3. The Sheet & Where you want to paste the filtered data precisely into Sheet x (Sheet 8 in my example)
Sheets("Sheet8").Activate
lr = ThisWorkbook.Worksheets("Sheet8").Cells(1, 1).SpecialCells(xlCellTypeLastCell).Row + 1
Range("A" & lr).Select
ActiveSheet.Paste
Application.DisplayAlerts = True
'4. Clear Filter from original sheet
On Error Resume Next
ws.Activate
ActiveSheet.ShowAllData
On Error GoTo 0
End Sub
What does the not-including the headers is this
ws.AutoFilter.Range.Copy 'copy the AutoFilter first
Set Rng = ws.UsedRange.Offset(1, 0)
Set Rng = Rng.Resize(Rng.Rows.Count - 1)
Rng.Copy
& your target is after you activate the target sheet and find its last row
lr = ThisWorkbook.Worksheets("Sheet8").Cells(1, 1).SpecialCells(xlCellTypeLastCell).Row + 1
I have a a sheet of data, and I want to filter based on the start of the policy number, and then I want to move all of the BFL policies after PFL policies. Row 1 contain all of the headers. My policy number starts with either PFL or BFL.
The reason why I can't sort Z-A directly because the raw data starts with BFL001 to BFL999 then PFL001 to PFL999 so sorting Z-A will get PFL999 first, but I want to just move everything from BFL001 to BFL999 after PFL001, like simple cut and paste. My range varies each month so I am using 001 to 999 to show you how my raw data is displayed.
After I run my current VBA module, it starts from row 1000 and from BFL001 to PFL999 which is not what I want. I need to start from PFL001 to PFL999 and then BFL001 to BFL999, and with no blank rows in between.
I am not sure if I can use partial search or use text like to find policies that starts with BFL then cut and paste to last row + 1. Not sure which way is faster.
Sub test()
Dim LR1 As Long
LR1 = Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
.Cut Range("A" & LR1 + 1)
End With
.AutoFilterMode = False
End With
End Sub
A neat trick with VBA is that you can reference certain cells that share a property using .SpecialCells in your case you'd want to use xlCellTypeVisible but there are many others that can be used.
The trick here is to do the cut manually. You can't cut cells that aren't right next to each other, but you can copy and paste them. So the idea is to paste the BFL cells below the PFL cells and then empty out the original cells and clean up the white spaces. After you apply the autofilter you can tell excel to only look at the visible cells within the same range that you specified before, so you don't get anything extra. This is important because when you go to clear all the visible cells, you don't want to accidentally clear the cells you just pasted below.
When you're cleaning up blank cells it's important to go from the bottom up because other wise you could run into indexing issues. You'll also notice that I use .entirerow so that it deletes the entire row instead of just the first column.
To show all of the data you simply go Worksheet.showalldata, BUT you need to check if there is even an autofilter applied to the sheet. Occasionally when you perform operations such as clearing cells, it'll turn off the autofilter, so it's best to check whether its still there or not so your macro doesn't throw an error at you.
One last tiny thing, although you're not wrong, it's not necessary to concatenate a string with the wildcard * you could simply have them within the same string. eg. "BFL*" vs "BFL" & "*" just saves a bit of time on typing.
Sub test()
Dim LR1 As Long
Dim BFLRange As Range
LR1 = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
Set BFLRange = .SpecialCells(xlCellTypeVisible)
BFLRange.Copy Destination:=Worksheets("Combined").Range("A" & LR1 + 1)
End With
BFLRange.Clear
For i = LR1 To 2 Step -1
If IsEmpty(.Cells(i, 1)) Then
.Cells(i, 1).EntireRow.Delete shift:=xlUp
End If
Next i
If .AutoFilterMode Then
.ShowAllData
End If
End With
End Sub
This snippet follows #SJR's suggestion where you delete the entire used region containing BFL. The reason I've disabled alerts is because there's just a little text box that pops up asking if you're sure you want to delete the sheet rows. By turning it off, it doesn't require any user input. It's good to note that by deleting the cells at once, it'll speed up the macro drastically if you're working with a large amount of data. Thanks again #SJR.
Sub test()
Dim LR1 As Long
Dim BFLRange As Range
LR1 = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
With Worksheets("Combined")
With .Range("A2:AU" & LR1)
.AutoFilter Field:=1, Criteria1:="BFL" & "*"
Set BFLRange = .SpecialCells(xlCellTypeVisible)
BFLRange.Copy Destination:=Worksheets("Combined").Range("A" & LR1 + 1)
End With
Application.DisplayAlerts = False
BFLRange.Delete
Application.DisplayAlerts = True
' For i = LR1 To 2 Step -1
' If IsEmpty(.Cells(i, 1)) Then
' .Cells(i, 1).EntireRow.Delete shift:=xlUp
' End If
' Next i
If .AutoFilterMode Then
.ShowAllData
End If
End With
End Sub
I am writing VBA for a file at work and need to do something a little odd. I need to highlight the row (not the entire row, just the used part of the row) if the cell in Column J contains a certain value. I have figured everything out except my code is highlighting the entire row, and I only want it to highlight the used cells in that row. Can anyone advise? Code below
'Yellow Highlight..........THIS IS HIGHLIGHTING THE WHOLE ROW....WHY!!!!! WHY!!!!!!!!!!!
Sheets("EMM").Activate
With Sheets("EMM")
For Lrow = 1 To ActiveSheet.UsedRange.Rows.Count
With .Cells(Lrow, "J")
If Not IsError(.Value) Then
If .Value = "Desk to adjust" Then
.EntireRow.Interior.ColorIndex = 6
End If
End If
End With
Next Lrow
End With
With Sheets("EMM")
For Lrow = 1 To .UsedRange.Rows.Count
With .Cells(Lrow, "J")
If Not IsError(.Value) Then
If .Value = "Desk to adjust" Then
Sheets("EMM").UsedRange.Rows(Lrow).Interior.ColorIndex = 6
End If
End If
End With
Next
End With
or using AutoFilter
With Sheets("EMM").UsedRange
.Parent.AutoFilterMode = False
.AutoFilter
.AutoFilter Field:=10, Criteria1:="Desk to adjust"
.Rows(1).Hidden = True 'Header row
.Interior.ColorIndex = 6
.Rows(1).Hidden = False 'Header row
.AutoFilter
.Cells(1, 1).Activate
End With
The easiest to avoid looping on the row and fetching non-blank cells, or setting up a filter, is to do this inside the IF:
.UsedRange.Rows(lRow).Interior.ColorIndex = 6
.UsedRange.Rows(lRow).SpecialCells(xlCellTypeBlanks).Interior.ColorIndex = 0
(highlight the row then unhighlight empty cells)
Here is some commented code showing how to use the Range.AutoFilter method to achieve the results you're looking for. No looping required, so it is generally much more efficient:
Sub tgrFilter()
Dim ws As Worksheet
Dim rngData As Range
Dim strMatch As String
Set ws = ActiveWorkbook.Sheets("EMM") 'We will be working with sheet "EMM" in activeworkbook
Set rngData = ws.Range("J1").CurrentRegion 'Get the region that column J is a part of in order to limit the highlighting (so it doesn't highlight entire row)
strMatch = "Desk to adjust" 'This is the string/value we are looking for in column J
rngData.Interior.Color = xlNone 'Clear any previous highlighting
On Error Resume Next 'If there are no results, it would cause an error
'Work with just column J within rngData
With Intersect(rngData, ws.Columns("J"))
.AutoFilter 1, strMatch 'Note that the filter is not case sensitive
'Color the matching rows contained in the data (not the entire row)
Intersect(rngData, .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).EntireRow).Interior.ColorIndex = 6
.AutoFilter 'Remove the filter
End With
If Err.Number <> 0 Then
'Error occurred which means there were no results
MsgBox "No matches found in column J for [" & strMatch & "]", , "No results"
Err.Clear
End If
On Error GoTo 0 'Remove the On Error Resume Next condition
End Sub
You can use Conditional Formatting instead of macro.
Select the cell your need to highlight and at menu bar go to Format -> Conditional Formatting
In dialog select condition you need to check, this example check if cell value is equal to 'AA'. You can add condition up to 3 conditions at a time
Next, Click format button to format cell when the condition is true.
After finish all click OK to close dialog you will get the highlight you need.
I am trying to delete entire rows with duplicate values. If the values in column "E" are the same in two rows, I want to delete all row with that value that is duplicated.
The other fields might be or not duplicates of that row and there might be up to ten duplicates and the total number of rows is large ( #rows >4000). This is just one part of a large macro, so I cannot use excel functions. This is what I have so far for deleting rows:
Sub AAAAH()
Application.ScreenUpdating = False
Dim i As Single
Dim j As Single
BottomLineRelease = Sheets("Hours Of Interest").Range("E" & Rows.Count).End(xlUp).Row + 1
rowcount = Sheets("Hours Of Interest").Range("E2:E" & BottomLineRelease).Rows.Count
For i = 2 To Sheets("Hours Of Interest").Cells(Rows.Count, "E").End(xlUp).Row
If Sheets("Hours Of Interest").Range("E" & i) = Sheets("Hours Of Interest").Range("E" & i - 1) Then
j = i - 1
Rows(j).Select
Selection.delete Shift:=xlUp
End If
Next i
Application.ScreenUpdating = True
End Sub
This not only crashes Excel, but the "Selection.delete Shift: =xlup" will not allow the "delete" to stay capitalized. Every time I click away, it goes back to lower case.
Does anyone know a faster or at least functional way to delete these duplicate rows in VBA?
Selection (=Application.Selection) is declared only as Object because it can take various objects (a range, a shape object, a chart etc. etc.). Therefore the intellisense doesn't work as well, it is only determined during execution if .Delete is a valid method.
Try
Sheets("Hours Of Interest").Rows(j).Delete Shift:=xlUp
If you use Sheets(...).Range in your code, you should never get lazy and never use Range or Rows or Cells without that explicit reference, you might be deleting on a different worksheet.
Furthermore, if you delete rows from the top down, every delete changes the row numbers of the following lines.
So you should delete backwars with
for i = [..maximum..] to 0 step -1
You don't need a loop to isolate unique values. You can filter column E for unique values, copy those to a new sheet, and delete the old sheet.
lastRow = Range("A1000000").End(xlUp).Row
Range("A1:H" & lastRow).AdvancedFilter Action:=xlFilterInPlace, _
CriteriaRange:=Range("E1:E" & lastRow), Unique:=True
Cells.Copy
Sheets.Add
ActiveSheet.Paste
Application.DisplayAlerts = False
Sheets("oldSheet").Delete
Application.DisplayAlerts = True
This is way faster than a loop, if memory serves.