Delete lines VBA macro takes a significant amount of time - excel

I have a macro that deletes lines based on a certain value in a column and then sorts them. It works fine. However, the worksheet starts with about 4000 rows and the macro ends up deleting about 2000 of them and it takes 1 minute 25 seconds to do it. I'm wondering if there's something I can do that will make it take a lot less time. Here's the code:
'remove numbers that are not allowed based on values in "LimitedElements" worksheet
For i = imax To 1 Step -1
a = Sheets("FatigueResults").Cells(i, 1).Value
Set b = Sheets("LimitedElements").Range("A:A")
Set c = b.Find(What:=a, LookIn:=xlValues)
If Not c Is Nothing Then
Sheets("FatigueResults").Rows(i).EntireRow.Delete
End If
Next i
'delete unecessary or redundant rows and columns
Rows(3).EntireRow.Delete
Rows(1).EntireRow.Delete
Columns(23).EntireColumn.Delete
Columns(22).EntireColumn.Delete
Columns(21).EntireColumn.Delete
Columns(20).EntireColumn.Delete
Columns(14).EntireColumn.Delete
Columns(13).EntireColumn.Delete
Columns(12).EntireColumn.Delete
Columns(11).EntireColumn.Delete
Columns(4).EntireColumn.Delete
Columns(3).EntireColumn.Delete
Columns(2).EntireColumn.Delete
'sort data
Dim strDataRange As Range
Dim keyRange As Range
Set strDataRange = Range("A:Q")
Set keyRange1 = Range("B1")
Set keyRange2 = Range("G1")
strDataRange.sort Key1:=keyRange1, Order1:=xlDescending, Key2:=keyRange2, Order2:=xlDescending, Header:=xlYes
'delete rows that are not in the included values For i = imax To 2 Step -1
If (Cells(i, 2).Value <> 0.04 And Cells(i, 2).Value <> 0.045 And Cells(i, 2).Value <> 0.05 And Cells(i, 2).Value <> 0.056 And Cells(i, 2).Value <> 0.063 And Cells(i, 2).Value <> 0.071 And Cells(i, 2).Value <> 0.08 And Cells(i, 2).Value <> 0.09 Or Cells(i, 3).Value <= 0) Then
ActiveSheet.Rows(i).EntireRow.Delete
End If
Next i

Add this at the beginning:
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Add this at the end:
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Also, instead of
If (Cells(i, 2).Value <> 0.04 And Cells(i, 2).Value <> 0.045 And Cells(i, 2).Value <> 0.05 And Cells(i, 2).Value <> 0.056 And Cells(i, 2).Value <> 0.063 And Cells(i, 2).Value <> 0.071 And Cells(i, 2).Value <> 0.08 And Cells(i, 2).Value <> 0.09 Or Cells(i, 3).Value <= 0) Then
ActiveSheet.Rows(i).EntireRow.Delete
End If
Use
Select Case Cells(i, 2)
Case 0.4, 0.045, 0.05, 0.056, 0.063, 0.071, 0.08, 0.09, Is < 0
'Do nothing
Case Else
ActiveSheet.Rows(i).EntireRow.Delete
End Select

I much prefer to build a string of rows to be deleted then do ONE delete. Here is a sample I put together for another post on here yesterday:
Sub DeleteRows()
Dim i As Long, DelRange As String
For i = 1 To Cells(Rows.Count, 6).End(xlUp).Row 'Doesn't matter which way you go when you delete in one go
If Left(Cells(i, 6), 3) = "314" Then DelRange = DelRange & "," & i & ":" & i 'Change the "314" as you see fit
Next i
Range(Right(DelRange, Len(DelRange) - 1)).Delete
End Sub
Also no need to worry about turning calculation or screen updating etc off when you only perform one deletion

Related

VBA expected end of statement

I am trying to edit my excel table with VBA but an error appears while compiling. It doesnt recognize line 2 and line 10.
Sub IfThenElse()
Dim i As Integer = 23
While Not IsNull(Cells(i, 35).Value)
If Cells(i, 35).Value > 1E+16 Then
Cells(i, 4).Value = Cells(i, 35).Value / 10
Else
Cells(i, 4).Value = Cells(i, 35).Value
i = i + 1
End If
End While
End Sub
You cannot declare a variable and set a value at the same time Dim i As Integer = 23
Row counts are of type Long not Integer, Excel has more rows than Integer can handle.
Dim i As Long
i = 23
While … End While is no valid syntax, you need to use Do While … Loop (see Do...Loop statement).
It is very unlikely that a cell value is Null if you are looking for an empty cell use IsEmpty or check for vbNullString
Do While Not IsEmpty(Cells(i, 35).Value) 'or Do While Not Cells(i, 35).Value = vbNullString
If Cells(i, 35).Value > 1E+16 Then
Cells(i, 4).Value = Cells(i, 35).Value / 10
Else
Cells(i, 4).Value = Cells(i, 35).Value
i = i + 1
End If
Loop
Not sure what exactly you are doing but i = i + 1 might need to come after End If.

For Loop in Worksheet change malfunction

Please I have an issue, everytime a change occcurs on the sheet it affects all the rows instead of the row (i) concerned. Confused. Don't for-loops work for worksheet_change ? Pls help. Thanks.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LR As Long
'create a variable for last row of column C, LR
LR = Cells(Rows.Count, "C").End(xlUp).Row
For i = 2 To LR
If Cells(i, 6) = "Yes" And Cells(i, 7).Value = "Full" Then
Target.Value = Cells(i, 3).Value
Cells(i, 9).ClearContents
Cells(i, 10).Value = Cells(i, 8).Value + Cells(i, 9).Value
End If
If Not Intersect(Target, Range("G" & i & ":G" & LR)) Is Nothing And Range("F" & i) = "Yes"
And Target.Value = "Full" Then
Application.EnableEvents = False
Cells(i, 8).Value = Cells(i, 3).Value
Cells(i, 9).ClearContents
Cells(i, 10).Value = Cells(i, 8).Value + Cells(i, 9).Value
Application.EnableEvents = True
End If
If Not Intersect(Target, Range("G" & i & ":G" & LR)) Is Nothing And Range("F" & i) = "Yes" And
Target.Value = "Portion" Then
Application.EnableEvents = False
Cells(i, 8).Value = Cells(i, 3).Value
Cells(i, 10).Value = Cells(i, 8).Value + Cells(i, 9).Value
Application.EnableEvents = True
End If
Next i
End Sub
It seems you need to launch this event for the columns A-E. So, you can start your macro with:
IF Target.Column <= 5 THEN
...
END IF 'at the end of your macro
Like this, when you launch code like Cells(i, 8).Value = ..., Cells(i, 10).Value = ..., ... this macro will be called but it will be stopped immediately.
Apparently you are checking on column, maximum 10, which is in the range of the cells you are changing within your macro. Let's go for another approach:
At the very beginning of your macro, put this line:
Application.EnableEvents = False
At the very end of your macro, put this line:
Application.EnableEvents = True
(and remove the other occurences).
This will make sure you don't call your macro while running it.

VLOOKUP across multiple workbooks

I am basically creating a VBA script to clean out a report sheet. I have everything downpacked but cannot figure out how to make VLOOKUP work to check on multiple workbooks. I basically have to match serial numbers on the report to serial numbers located either on folder A or Folder B.
As of right now, I have manually set the Range().Value =VLOOKUP for only one workbook but If I do it for a second then it might create conflicts. However, I want to know if it's possible to VLOOKUP an entire column from the LastRow up and ignore blanks while checking both workbooks.
Sub LowTonerSOC()
Dim i As Long
For i = Cells(Rows.Count, "J").End(xlUp).Row To 2 Step -1
If Cells(i, "J") <> "Yes" Then Rows(i).Delete
Next i
For i = Cells(Rows.Count, "K").End(xlUp).Row To 2 Step -1
If Cells(i, "K") <> "Yes" Then Rows(i).Delete
Next i
For i = Cells(Rows.Count, "O").End(xlUp).Row To 2 Step -1
If Cells(i, "O") <> "Headquarters" And Cells(i, "O") <> "INDUSTRIAL" And Cells(i, "O") <> "VAUSA" Then Rows(i).Delete
Next i
Columns(1).EntireColumn.Delete
Columns(1).EntireColumn.Delete
Columns(1).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Columns(7).EntireColumn.Delete
Range("C:F" & LastRow).Replace "", "999", xlWhole
For i = Cells(Rows.Count, "A").End(xlUp).Row To 2 Step -1
If Cells(i, "C").Value2 >= 10 And Cells(i, "D").Value2 >= 10 And Cells(i, "E").Value2 >= 10 And Cells(i, "F").Value2 >= 10 Then
Rows(i).Delete
End If
Next i
For i = Cells(Rows.Count, "C").End(xlUp).Row To 2 Step -1
If Cells(i, "C").Value2 <= 10 Then
Cells(i, "C").Interior.ColorIndex = 15
End If
Next i
For i = Cells(Rows.Count, "D").End(xlUp).Row To 2 Step -1
If Cells(i, "D").Value2 <= 10 Then
Cells(i, "D").Interior.ColorIndex = 8
End If
Next i
For i = Cells(Rows.Count, "E").End(xlUp).Row To 2 Step -1
If Cells(i, "E").Value2 <= 10 Then
Cells(i, "E").Interior.ColorIndex = 3
End If
Next i
For i = Cells(Rows.Count, "F").End(xlUp).Row To 2 Step -1
If Cells(i, "F").Value2 <= 10 Then
Cells(i, "F").Interior.ColorIndex = 6
End If
Next i
Application.Calculation = xlAutomatic
Range("C:F" & LastRow).Replace "999", "", xlWhole
ActiveSheet.Name = "Sheet1"
Range("G1").Value = "Physical Location"
Range("G2").Value = "=VLOOKUP(B2,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G3").Value = "=VLOOKUP(B3,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G4").Value = "=VLOOKUP(B4,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G5").Value = "=VLOOKUP(B5,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G6").Value = "=VLOOKUP(B6,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G7").Value = "=VLOOKUP(B7,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G8").Value = "=VLOOKUP(B8,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G9").Value = "=VLOOKUP(B9,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G10").Value = "=VLOOKUP(B10,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G11").Value = "=VLOOKUP(B11,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G12").Value = "=VLOOKUP(B12,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G13").Value = "=VLOOKUP(B13,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G14").Value = "=VLOOKUP(B14,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G15").Value = "=VLOOKUP(B15,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G16").Value = "=VLOOKUP(B16,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G17").Value = "=VLOOKUP(B17,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G18").Value = "=VLOOKUP(B18,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G19").Value = "=VLOOKUP(B19,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G20").Value = "=VLOOKUP(B20,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G21").Value = "=VLOOKUP(B21,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G22").Value = "=VLOOKUP(B22,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G23").Value = "=VLOOKUP(B23,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G24").Value = "=VLOOKUP(B24,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G25").Value = "=VLOOKUP(B25,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G26").Value = "=VLOOKUP(B26,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G27").Value = "=VLOOKUP(B27,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G28").Value = "=VLOOKUP(B28,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G29").Value = "=VLOOKUP(B29,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Range("G30").Value = "=VLOOKUP(B30,'\\spwsrf\Deskside\Desktop\EUS\AssestInventory\Printers\[Printers.xlsm]Sheet1'!$F$1:$G$230,2,0)"
Application.ScreenUpdating = False
Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
End Sub
Pick column that has no blank in setting last row to vlookup in entire column
LastRow = WorksheetFunction.Max(Sheets("Sheet1").Cells(Rows.Count, "E").End(xlUp).Row, 9)
then for vlookup that has multiple workbook, set your workbooks
Sub VlookMultipleWorkbooks()
Dim lookFor as String
Dim srchRange as Range
Dim book1 as Workbook
Dim book2 as Workbook
'Set some Workbook variables:
Set book1 = Workbooks("Book 1 Name") '<edit as needed
Set book2 = Workbooks("Book 2 Name") '<edit as needed
'Set a string variable that we will search for:
lookFor = book2.sheets(5).range(Cells(j, c + 1))
'Define the range to be searched in Book1.Sheets(4):
Set srchRange = book1.Sheets(4).Range(cells(row1+2,1).Address, cells(row2,col1).Address)
'This assumes that the Book2 is Open and you are on the desired active worksheet:
ActiveSheet.Cells(j, c + 2).value = _
Application.WorksheetFunction.VLookup(lookFor, _
book1.Sheets(4).Range(srchRange.Address), 3, False)
End Sub
refer to this link for vlookup with multiple vlookup Sub VlookupMultipleWorkbook

VBA and passing values

I'm trying to compare data between two worksheets. Each Worksheet has three column: A is a concatenation of a Customer and a SKU, B is the sales volume and C is for measuring volume discrepancies. I aim to do two things, check Sheet1 for SKUs that are not in Sheet2 and then, if SKUs match on both sheets, check their volume for quantity differences. If Sheet 1 has a SKU not in Sheet2, I want the record highlighted. I've accomplished this in a primitive way, the entire row gets highlighted. I am, however, having trouble getting the code to check volumes if the Customer & SKU match. I was hoping VBA would retain the values of the cells it was checking, where have I gone wrong and what is the proper implementation? Sorry for being such a n00b.
Sub Again()
Dim lastRow As Integer
Dim rng As Range
lastRow = Sheets("Sheet1").Range("A65000").End(xlUp).Row
For i = 1 To lastRow
Set rng = Sheets("sheet2").Range("A:A").Find(Sheets("Sheet1").Cells(i, 1))
If rng Is Nothing Then
Sheets("Sheet1").Cells(i, 3) = "Item not in sheet2"
Sheets("Sheet1").Cells(i, 1).EntireRow.Interior.Color = vbRed
ElseIf Not rng Is Nothing Then
If Sheets("sheet1").Cells(i, 2).Value - Sheets("sheet2").Cells(i, 2).Value < -5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet2 reports " & Sheets("sheet1").Cells(i, 2).Value - Sheets("sheet2").Cells(i, 2).Value & " more units of volume."
ElseIf Sheets("sheet1").Cells(i, 2) - Sheets("sheet2").Cells(i, 2) > 5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet1 reports " & Sheets("sheet1").Cells(i, 2) - Sheets("sheet2").Cells(i, 2) & " more units of volume."
Else: Sheets("sheet1").Cells(i, 3) = "No or insignificant discrepancy"
End If
End If
Next
End Sub
I think you need to reuse rng like this:
rng.offset(2,0).value
in place of:
Sheets("sheet2").Cells(i, 2).Value
Because all your currently doing is assuming that the matching cell is in exactly the same row as in sheet1.
Your code should then look something like this:
Sub Again()
Dim lastRow As Integer
Dim rng As Range
lastRow = Sheets("Sheet1").Range("A65000").End(xlUp).Row
For i = 1 To lastRow
Set rng = Sheets("sheet2").Range("A:A").Find(Sheets("Sheet1").Cells(i, 1))
If rng Is Nothing Then
Sheets("Sheet1").Cells(i, 3) = "Item not in sheet2"
Sheets("Sheet1").Cells(i, 1).EntireRow.Interior.Color = vbRed
ElseIf Not rng Is Nothing Then
If Sheets("sheet1").Cells(i, 2).Value - rng.offset(0, 2).Value < -5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet2 reports " & Sheets("sheet1").Cells(i, 2).Value - rng.offset(0, 2).Value & " more units of volume."
ElseIf Sheets("sheet1").Cells(i, 2) - rng.offset(0, 2).Value > 5 Then
Sheets("sheet1").Cells(i, 3) = "Sheet1 reports " & Sheets("sheet1").Cells(i, 2) - rng.offset(0, 2).Value & " more units of volume."
Else: Sheets("sheet1").Cells(i, 3) = "No or insignificant discrepancy"
End If
End If
Next
End Sub
Variables. ...If I understand your questions correctly.
dim myString as String
dim myFloat as Float

Matching pairs of cells while iterating through columns to then return a new pair of cells

I am trying to write a code that will take one cell and then iterate through another column to find a match, once it has found a match it will then match two other cells in that same row and return the value of a 5th and 6th cell. However, it is not working! any suggestions??
Sub rates()
Dim i As Integer
For i = 2 To 2187
If Cells(i, 1).Value = Cells(i, 11).Value Then
If Cells(i, 2).Value = Cells(i, 12).Value Then
Cells(i, 20) = Cells(i, 1).Value
Cells(i, 21) = Cells(i, 11).Value
Cells(i, 22) = Cells(i, 4).Value
Cells(i, 23) = Cells(i, 16).Value
Else
Cells(i, 24) = "No match"
End If
End If
Next i
End Sub
Try fully qualifying your cell objects i.e. sheet1.cells(i,1).value etc or encase within a with statement i.e.
with sheet1
if .cells(i,X) = .cells(i,Y) then
'...etc
end with
I think the default property for a range is "Value" but try putting .Value on to the end of all those Cell lines too... like you have for half of them :)
[EDIT/Addition:]
... failing that, you're not actually searching a whole column at any point: try something like:
Sub rates()
Dim i As Integer
Dim rgSearch As Range
Dim rgMatch As Range
Dim stAddress As String
Dim blMatch As Boolean
With wsSheet
Set rgSearch = .Range(.Cells(x1, y1), .Cells(x2, y2)) ' Replace where appropriate (y = 1 or 11 i guess, x = start and end row)
End With
For i = 2 To 2187
Set rgMatch = rgSearch.Find(wsSheet.Cells(i, y)) ' y = 1 or 11 (opposite of above!)
blMatch = False
If Not rgMatch Is Nothing Then
stAddress = rgMatch.Address
Do Until rgMatch Is Nothing Or rgMatch.Address = stAddress
If rgMatch.Offset(0, y).Value = Cells(i, 12).Value Then
Cells(i, 20) = Cells(i, 1).Value
Cells(i, 21) = Cells(i, 11).Value
Cells(i, 22) = Cells(i, 4).Value
Cells(i, 23) = Cells(i, 16).Value
blMatch = True
Else
End If
Set rgMatch = rgSearch.FindNext(rgMatch)
Loop
End If
If Not blMatch Then
Cells(i, 24) = "No match"
End If
Next i
End Sub
I've made a lot of assumptions in there and there's a few variables you'll have to replace. You could also probably use application.worksheetfunction.match but .find is quicker and more awesome

Resources