My VBA code is getting slower every iteration - excel

I'm using the code to add a column, bucket the value on left (via a vlookup) and then auto fill the whole column. The problem I'm having is every time I use the macro, the code is taking slightly longer and longer. Would appreciate any help :)
Here is the code:
Sub insert_col()
'
' insert_col Macro
'
' Keyboard Shortcut: Ctrl+w
'
Dim x As Variant
Dim a As Long
Dim b As Long
Dim y As Variant
Dim t As Single
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
t = Timer
ActiveSheet.Columns(ActiveCell.Column).EntireColumn.Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
x = ActiveCell.Column
Cells(22, x).Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-1],R13C1:R193C2,1)"
Cells(22, x).Select
a = ActiveCell.Column
x = ActiveCell.Row
y = ActiveCell.End(xlDown).Row
Selection.AutoFill Destination:=Range(Cells(x, a), Cells(36600, a)), Type:=xlFillDefault
ActiveCell.Offset(0, 2).Select
MsgBox Timer - t
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Thanks!

To be clearer on the comment above, your code adds additional formulae each time it is run which increases the calculation time.
You can greater simply the code along the lines below:
Sub insert_col()
' Keyboard Shortcut: Ctrl+w
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
t = Timer
ActiveCell.EntireColumn.Insert
Range(Cells(22, ActiveCell.Column), Cells(36600, ActiveCell.Column)).FormulaR1C1 = "=VLOOKUP(RC[-1],R13C1:R193C2,1)"
ActiveCell.Offset(0, 2).Select
MsgBox Timer - t
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub

Related

How to fill down functions in four columns to where the data in column A stops?

I am trying to fill down functions in four columns to where the data in column A stops, but by the time it gets to the fourth FillDown, it takes a very long time.
Is there any way to rewrite it more efficiently?
Range("D2").Select
ActiveCell.FormulaR1C1 = "=LEFT(RC[-1],2)"
Range(ActiveCell, ActiveCell.Offset(0, 0).End(xlDown)).FillDown
Range("E2").Select
ActiveCell.FormulaR1C1 = "=MID(RC[-2],7,2)"
Range(ActiveCell, ActiveCell.Offset(0, 0).End(xlDown)).FillDown
Range("Z2").Select
ActiveCell.FormulaR1C1 = "=IF(RC[-22]<>""SO"",RC[-22],RC[-12])"
Range(ActiveCell, ActiveCell.Offset(0, 0).End(xlDown)).FillDown
Range("AA2").Select
ActiveCell.FormulaR1C1 = _
"=IF(OR((RC[-22]=""17""),(RC[-22]<>""11""),(RC[-23]=""SO"")),""HQ"",""Remote"")"
Range(ActiveCell, ActiveCell.Offset(0, 0).End(xlDown)).FillDown
I see several issues here
You say ... to where the data in column A stops but are using .End(xlDown) on columns D, E, Z, AA. This may be filling the formula down to the botton of the sheet.
You don't need to Fill Down, simply apply the formula to a specified range
Select is not a needed
Consider this
Sub Demo()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = ActiveSheet ' or specify the required sheet
With ws
' find where data in column A stops
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
If LastRow = 1 Then
' there is no data in column A
Exit Sub
End If
.Range(.Cells(2, 4), .Cells(LastRow, 4)).FormulaR1C1 = "=LEFT(RC[-1],2)"
.Range(.Cells(2, 5), .Cells(LastRow, 5)).FormulaR1C1 = "=MID(RC[-2],7,2)"
.Range(.Cells(2, 26), .Cells(LastRow, 26)).FormulaR1C1 = "=IF(RC[-22]<>""SO"",RC[-22],RC[-12])"
.Range(.Cells(2, 27), .Cells(LastRow, 27)).FormulaR1C1 = "=IF(OR((RC[-22]=""17""),(RC[-22]<>""11""),(RC[-23]=""SO"")),""HQ"",""Remote"")"
End With
End Sub
As #BigBen pointed out, you can avoid using .FillDown by just referencing the full range from the start. You can also avoid .Select at the same time by using functions like .Resize to reference larger ranges based on the current range.
Additionally, since your macro is writing formulas into cells, you can speed up the code by disabling the auto-calculation that happens whenever a cell is edited. It's also a good idea to disable any events that might be running from the Worksheet_Change procedure.
You can disable those two things using Application.Calculation = xlCalculationManual and Application.EnableEvents = False. After the code, you will want to return those two settings back to default with Application.Calculation = xlCalculationAutomatic and Application.EnableEvents = True
Here's an example of how to implement these suggestions:
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
With Range("D2")
.Resize(.End(xlDown).Row - .Row).FormulaR1C1 = "=LEFT(RC[-1],2)"
End With
With Range("E2")
.Resize(.End(xlDown).Row - .Row).FormulaR1C1 = "=MID(RC[-2],7,2)"
End With
With Range("Z2")
.Resize(.End(xlDown).Row - .Row).FormulaR1C1 = "=IF(RC[-22]<>""SO"",RC[-22],RC[-12])"
End With
With Range("AA2")
.Resize(.End(xlDown).Row - .Row).FormulaR1C1 = _
"=IF(OR((RC[-22]=""17""),(RC[-22]<>""11""),(RC[-23]=""SO"")),""HQ"",""Remote"")"
End With
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
I preserved the .End(xlDown) method since I don't know what your sheet looks and that may be the best method to match your data format.

How to use VBA to loop through cutting a range of cells and pasting into next row

The purpose of this VBA is to make a single long row of values (tens of thousands) into something more readable by keeping each row limited to 22 values. I have a manual version of this which works for 200 rows, but am hoping to use looping to save myself time and hopefully improve performance.
Example:
I have values in A1:ZZ1 and am trying to cut W1:ZZ1 and paste into A2, then cut W2:ZD2 and paste into A3 until there are no values left to cut and paste.
I'm using Excel 2010.
Sub InsertScript22perLine()
'Turn off screen updating to speed up macro
Application.ScreenUpdating = False
Range("W1").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Cut
Selection.End(xlToLeft).Select
Range("A2").Select
ActiveSheet.Paste
Range("W2").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Cut
Selection.End(xlToLeft).Select
Range("A3").Select
ActiveSheet.Paste
'Turn screen updating back on
Application.ScreenUpdating = True
End Sub
Sub InsertScript22perLine()
Application.ScreenUpdating = False
' Starting column for input data
Dim sStartCol As String
Dim lStartCol As Long
' Count of columns
Dim lColCount As Long
' Count of columns of data for output
Dim lRowLen As Long
lRowLen = 22
Dim lRow As Long
lRow = 2
sStartCol = "W"
lStartCol = Range(sStartCol & 1).Column
' Get the column count
lColCount = Cells(1, Columns.Count).End(xlToLeft).Column
For a = lStartCol To lColCount Step lRowLen
Range(Cells(lRow, 1), Cells(lRow, lRowLen)).Value = Range(Cells(1, a), Cells(1, a + lRowLen)).Value
lRow = lRow + 1
Next
Application.ScreenUpdating = True
End Sub

Speed up VBA code on extracting relevant rows to new worksheet

I need to copy relevant rows to a new Excel worksheet. The code will loop through each row in the original worksheet and select rows based on relevant countries and products specified in the array into the second worksheet.
Private Sub CommandButton1_Click()
a = Worksheets("worksheet1").Cells(Rows.Count, 2).End(xlUp).Row
Dim countryArray(1 To 17) As Variant
Dim productArray(1 To 17) As Variant
' countryArray(1)= "Australia" and so on...
' productArray(1)= "Product A" and so on...
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
For i = 3 To a
For Each j In countryArray
For Each k In productArray
Sheets("worksheet1").Rows(i).Copy Destination:=Sheets("worksheet2").Range("A" & Rows.Count).End(xlUp).Offset(1)
Next
Next
Next
Application.CutCopyMode = False
Application.ScreenUpdating = False
End Sub
Each time I ran the code, the spreadsheet stopped responding in a matter of minutes. Would appreciate if someone could help me on this, thanks in advance!
Here are some pointers:
Remember to declare all your variables and use Option Explicit at the top of your code
Use With statements to ensure working with right sheet and not implicit activesheet or you may end up with wrong end row count
Only i contributes to the loop so you are making unnecessary loop work
Gather qualifying ranges with Union and copy in one go
Remember to switch back on screen-updating
Code:
Option Explicit
Private Sub CommandButton1_Click()
Dim unionRng As Range, a As Long, i As Long
With Worksheets("worksheet1")
a = .Cells(.Rows.Count, 2).End(xlUp).Row
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
For i = 3 To a
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, .Cells(i, 1))
Else
Set unionRng = .Cells(i, 1)
End If
Next
With Worksheets("worksheet2")
unionRng.EntireRow.Copy .Cells(.Rows.Count, "A").End(xlUp).Row +1
End With
End With
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub

Excel For Each Cell Not Working?

I am trying to get the code to loop through the range. For example, it should be taking the value in cell M53, using it, then running through the code, and doing the same thing with the value in cell M54. The first iteration works, but then it just seems to continuously keep running in cell M53.
I am struggling to work this one out.
Sub TestMacro1()
Dim n As Integer
Dim Strike As Range
Set Strike = Range("M53:M54")
n = 1
Application.ScreenUpdating = False
For Each cell In Strike
cell.Select
Selection.Copy
Range("E19").PasteSpecial xlPasteValues
If Checker = True Then
Range("E26").Select
Selection.Copy
Range("N53").Offset(n).PasteSpecial xlPasteValues
n = n + 1
End If
Next cell
Application.ScreenUpdating = True
End Sub
The Checker Function is defined as:
Function Checker() As Boolean
Dim tmp
Dim c As Object
tmp = False
ActiveSheet.Calculate
ActiveSheet.Calculate
With ActiveSheet.UsedRange
Set c = .Find("request", LookIn:=xlValues)
If Not c Is Nothing Then
Application.OnTime Now + TimeValue("00:00:06"), "TestMacro1"
tmp = False
Else
tmp = True
End If
End With
Checker = tmp
End Function
Please try this.
Sub TestMacro2()
Sub TestMacro2()
Dim cell As Range
Dim Strike As Range
Set Strike = Range("M53:M54")
Application.ScreenUpdating = False
For Each cell In Strike
cell.Copy
Range("E19").PasteSpecial xlPasteValues 'fixed range
If Checker = True Then
ActiveSheet.Calculate
Range("E26").Copy
cell.Offset(0, 1).PasteSpecial xlPasteValues
End If
Next cell
Application.ScreenUpdating = True
End Sub

How can i repeat the macro for the whole range of cells and columns?

Basically i'm linking the cells of workbook1 with workbook2, what is the code to do that for the whole spreadsheet?
my fault not clearly explained, as you can see below i'm assigning the value of the cells in workbook1 from workbook2
Sub Macro2()
Windows("workbook2.xlsx").Activate
Windows("workbook1.xlsx").Activate
ActiveCell.FormulaR1C1 = _
"='[workbook2.xlsx]workbook1'!R18C1"
Range("A19").Select
ActiveCell.FormulaR1C1 = _
"='[workbook2.xlsx]workbook1'!R19C1"
Range("A20").Select
.........
End Sub
i was wondering whats the fastest way to do that for the range A9 to A120, E9 to E120, F9 to F120.....
This code will link all cells in all worksheets:
Sub LinkSheets()
Dim ws As Worksheet
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
For Each ws In Worksheets
ws.UsedRange.FormulaR1C1 = "='[workbook2.xlsx]" & ws.Name & "'!RC"
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
If you only want to link certain cells from one workhsheet, try this code:
Sub LinkRange()
Workbooks("workbook1.xlsx").Worksheets("Sheet1"). _
Range("A9:A120,E9:E120,F9:F120").FormulaR1C1= _
"='[workbook2.xlsx]Sheet1'!RC"
End Sub
Sub CopyPasteEntries()
Dim i, g, h As Integer
Sheets("Sheet1").Select
Range("A1").EntireRow.Copy
Sheets("Sheet2").Range("A1").PasteSpecial Paste:=xlPasteAll
i = 2
Sheets("Sheet1").Select
Do Until IsEmpty(Cells(i, 1))
i = i + 1
Loop
g = i - 1
h = 2
For i = 2 To g
Sheets("Sheet1").Select
If Cells(i, 1).Value <> "Created" Then
Cells(i, 1).EntireRow.Copy
Sheets("Sheet2").Select
Cells(h, 1).Select
ActiveCell.PasteSpecial xlPasteAll
h = h + 1
End If
Next
Application.CutCopyMode = False
End Sub

Resources