VBA Excel Code Running Much slower in 2010 than 2007 - vba

I have some code that runs fine in Excel 2007 but when used in Excel 2010 takes about ten times longer to run and causes the whole taskbar/other programs to be unresponsive.
I don't believe hardware is the problem because the computer running Excel 2007 is a Pentium 4 with 2 gigs of ram, while the computer running 2010 is an i7 with 8 gigs of ram.
Here is the code itself:
Sub Macro6()
With Application
.ScreenUpdating = False 'Prevent screen flickering
.Calculation = xlCalculationManual 'Preventing calculation
.DisplayAlerts = False 'Turn OFF alerts
.EnableEvents = False 'Prevent All Events
End With
Dim i As Integer
Dim j As Integer
Dim Anc As String
Dim MSA As String
j = 1
Do
i = 0
MSA = ActiveCell
Selection.Copy
Sheets("Sheet1").Select
ActiveCell.Offset(0, -2).Select
ActiveSheet.Paste
ActiveCell.Offset(0, 2).Select
Sheets("wip").Select
Do
i = i + 1
ActiveCell.Offset(0, 1).Select
Anc = ActiveCell.Offset(-j, 0)
Selection.Copy
Sheets("Sheet1").Select
ActiveCell.Offset(0, -1) = Anc
ActiveCell.Offset(0, -2) = MSA
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Select
Sheets("wip").Select
Loop Until IsEmpty(ActiveCell.Offset(0, 1))
j = j + 1
ActiveCell.Offset(1, -i).Select
Loop Until IsEmpty(ActiveCell)
'Speeding Up VBA Code
With Application
.ScreenUpdating = True 'Prevent screen flickering
.Calculation = xlAutomatic 'Preventing calculation
.DisplayAlerts = True 'Turn OFF alerts
.EnableEvents = True 'Prevent All Events
End With
End Sub
The code does what I want it to, but I am concerned as to why in 2010 there is such a difference in running time?

Is this what you are trying to do?
Option Explicit
Sub Sample()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim i As Long, j As Long, k As Long, lRow As Long, lCol As Long
On Error GoTo Whoa
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
'~~> Setting the worksheets to work with
Set ws1 = Sheets("wip"): Set ws2 = Sheets("Sheet1")
'~~> Setting the start cell in "Sheet1"
k = 3
With ws1
'~~> Get the last row in Col A of "wip"
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Get the last column in row 3 of "wip"
lCol = .Cells(3, .Columns.Count).End(xlToLeft).Column
'~~> Looping through rows in Col A in "wip"
For i = 3 To lRow
'~~> Looping through columns in the relevant row in "wip"
For j = 3 To lCol + 1
'~~> Writing output directly in "Sheet1"
ws2.Cells(k, 1).Value = ws1.Cells(i, 1).Value
ws2.Cells(k, 3).Value = ws1.Cells(i, 1).Offset(, j - 2).Value
k = k + 1
Next j
Next i
End With
LetsContinue:
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub

Related

Editing code to stop user from jumping from sheet to sheet

I have some code that copies data from one sheet on to another and then deletes empty rows. The code kind of works, but i sends the user from sheet to sheet while doing it. I am still new to VBA and im now sure how to achieve the result without using the select property. What I need to code to do, is move data from one sheet to another and delete empty rows when a button is clicked. I want the user to stay on the front page while the code executes. My code is below:
Sub MarkSold()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("on stock").Range("B" & CStr(LSearchRow)).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & CStr(LSearchRow)).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Select
Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Select
Selection.Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Select
Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Select
ActiveSheet.Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
Sheets("On stock").Select
End If
LSearchRow = LSearchRow + 1
Wend
Dim sh As Worksheet
Dim lr As Long, i As Long
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
'Position on cell A3
Application.CutCopyMode = False
Sheets("Data Entry").Range("A1").Select
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub
Any help is appreciated!
Just remove the .Select statement from your code and set refer your code directly to each sheet. Just like The code below:
Sub MarkSold()
Dim LSearchRow As Integer
Dim LCopyToRow As Integer
Set stock = Sheets("On stock")
Set tSold = Sheets("Turbines sold")
Set dEntry = Sheets("Data Entry")
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("on stock").Range("B" & CStr(LSearchRow)).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & CStr(LSearchRow)).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Rows(CStr(LSearchRow) & ":" & CStr(LSearchRow)).Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Rows(CStr(LCopyToRow) & ":" & CStr(LCopyToRow)).Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
End If
LSearchRow = LSearchRow + 1
Wend
Dim sh As Worksheet
Dim lr As Long, i As Long
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
Application.CutCopyMode = False
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub
I've cleaned up your code a little and commented on it, so you can follow the reasoning for the changes:
Sub MarkSold()
Dim sh As Worksheet
Dim lr As Long
Dim i As Long
Dim LSearchRow As Long
Dim LCopyToRow As Long
'the variables above ought to be declared as Long instead of Integer, as there
'are more cells in Excel than there are Integer values
On Error GoTo Err_Execute
'Start search in row 6
LSearchRow = 6
'Start copying data to row 6 in Sheet3 (row counter variable)
LCopyToRow = 6
While Len(Sheets("On stock").Range("B" & LSearchRow).Value) > 0
'If value in column B = "D5", copy entire row to Sheet3
If Sheets("On stock").Range("B" & LSearchRow).Value = Sheets("Data Entry").Range("D5") Then
'Select row in Sheet1 to copy
Sheets("On stock").Rows(LSearchRow).Cut
'Paste row into Sheet2 in next row
Sheets("Turbines sold").Rows(LCopyToRow).Paste
'Move counter to next row
LCopyToRow = LCopyToRow + 1
'Go back to Sheet1 to continue searching
End If
LSearchRow = LSearchRow + 1
Wend
Set sh = Sheets("On stock")
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
lr = sh.Cells(Rows.Count, 1).End(xlUp).Row
For i = lr To 6 Step -1
If WorksheetFunction.CountA(Rows(i)) = 0 Then
Rows(i).EntireRow.Delete
End If
Next i
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.ScreenUpdating = True
End With
Call setupDV
'Position on cell A3
Application.CutCopyMode = False
Sheets("Data Entry").Range("A1").Select
'Do you really need the select command above?
MsgBox "Now marked as sold!"
Exit Sub
Err_Execute:
'MsgBox "An error occurred."
End Sub

Summary sheet created from multiple worksheets using a dynamic range

I have a 176 worksheets in a workbook, that all have the same format/structure, but are a difference size in row length.
I want to copy the data that is held in range A10:V(X) where X is a calculable number. This data will be pasted underneath each other, in columns B:W of the main sheet "RDBMergeSheet" and the name of the sheet that each row came from will be pasted into Column A of RDBMergeSheet so it can be seen which rows came from which sheets
X = (The lowest used row number in column J) - 3
If it makes it easier, another way to calculate X is find the row number in column A that contains the word "total" and subtract 1 from it.
The following link contains an example of such a sheet, with sanitised data.
https://imgur.com/a/emlZj
The code I've got so far, with help, is:
Sub ImportData()
Dim x As Long
Dim LR As Long
Dim wks As Worksheet
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Set wks = Sheets("RDBMergeSheet"): If Not wks Is Nothing Then wks.Delete
Set wks = Worksheets.Add(after:=Worksheets(Sheets.Count))
wks.Name = "RDBMergeSheet"
For x = 1 To Worksheets.Count - 1
LR = Application.Max(1, Sheets(x).Cells(Rows.Count, 10).End(xlUp).Row - 3)
With wks.Cells(Rows.Count, 1)
.Offset(1, 1).Resize(LR, 22).Value = .Cells(1, 10).Resize(LR, 22).Value
.Offset(1).Resize(LR - 9).Value = Sheets(x).Name
End With
Next x
wks.Select
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Set wks = Nothing
End Sub
This errors out with a 1004: Application defined or object defined error on line
.Offset(1, 1).Resize(LR, 22).Value = .Cells(1, 10).Resize(LR, 22).Value
If anyone has any ideas on either how to resolve this I would be extremely grateful.
Please give this a try and tweak it as per your requirement to make sure the correct data is copied starting from the correct row on destination sheet.
Sub ImportData()
Dim LR As Long, dLR As Long, i As Long
Dim wks As Worksheet
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
On Error Resume Next
Set wks = Sheets("RDBMergeSheet")
wks.Cells.Clear
On Error GoTo 0
If wks Is Nothing Then
Set wks = Worksheets.Add(after:=Worksheets(Sheets.Count))
wks.Name = "RDBMergeSheet"
End If
For i = 1 To Worksheets.Count - 1
If Worksheets(i).Name <> wks.Name Then
LR = Application.Max(1, Sheets(i).Cells(Rows.Count, 10).End(xlUp).Row - 3)
If LR > 9 Then
If wks.Range("B1").Value = "" Then
dLR = 1
Else
dLR = wks.UsedRange.Rows.Count + 1
End If
wks.Range("B" & dLR & ":X" & LR - 9).Value = Worksheets(i).Range("B10:X" & LR).Value
wks.Range("A" & dLR).Value = Worksheets(i).Name
End If
End If
Next i
On Error Resume Next
wks.Select
dLR = wks.UsedRange.Rows.Count
wks.Range("A1:A" & dLR).SpecialCells(xlCellTypeBlanks).Formula = "=R[-1]C"
wks.Range("A1:A" & dLR).Value = wks.Range("A1:A" & dLR).Value
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
Set wks = Nothing
End Sub

Delete row if the column contains text

I known, this question has been asked thousands of times. But every time I picked up a solution appears error when i debug. (error 1004)
I work with a database with about 300000 lines, where more than half do not care. (I know that have filter, but wanted to erase to reduce the file and speed up the process).
Then if the column M has a keyword like "water", "beer" or "vodka" it will delete the row. I mean, don't need to be the exact word, just the keyword.
OBS: Row 1 it's a table title with the frozen line.
Thanks!
The following code works less than 4 seconds for processing your sample data on my machine:
Sub QuickDeleteRows()
Dim Sheet_Data As Worksheet, NewSheet_Data As Worksheet, Data As Range
Dim Sheet_Name As String, Text As String, Water As Long, Beer As Long, Vodka As Long
On Error GoTo Error_Handler
SpeedUp True
Set Sheet_Data = Sheets("SOVI")
Sheet_Name = Sheet_Data.Name
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
ReDim Output(1 To LastRow - 1, 1 To 1) As Long
For i = 1 To LastRow - 1
Text = Cells(i + 1, 13)
Water = InStr(Text, "water")
Beer = InStr(Text, "beer")
Vodka = InStr(Text, "vodka")
If Water > 0 Or Beer > 0 Or Vodka > 0 Then Output(i, 1) = 1
Next
[S2].Resize(LastRow - 1, 1) = Output
LastColumn = Cells(2, Columns.Count).End(xlToLeft).Column
Set Data = Sheet_Data.Range(Cells(1, 1), Cells(LastRow, LastColumn))
Set NewSheet_Data = Sheets.Add(After:=Sheet_Data)
Data.AutoFilter Field:=19, Criteria1:="=1"
Data.Copy
With NewSheet_Data.Cells
.PasteSpecial xlPasteColumnWidths
.PasteSpecial xlPasteAll
.Cells(1, 1).Select
.Cells(1, 1).Copy
End With
Sheet_Data.Delete
NewSheet_Data.Name = Sheet_Name
NewSheet_Data.Columns(19).Clear
Safe_Exit:
SpeedUp False
Exit Sub
Error_Handler:
Resume Safe_Exit
End Sub
Sub SpeedUp(SpeedUpOn As Boolean)
With Application
If SpeedUpOn Then
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
.DisplayStatusBar = False
.DisplayAlerts = False
Else
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.DisplayAlerts = True
End If
End With
End Sub
In the future, please post code you've tried first for the community to help you out. That being said, try this out:
Sub Test()
Dim x as Long
Dim i as Long
x = Sheets("SOVI").Range("M" & Rows.Count).End(xlUp).Row
For i = x to 2 Step -1
If InStr(1, Range("M" & i).Value, "water", vbTextCompare) Or InStr(1, Range("M" & i).Value, "beer", vbTextCompare) Or InStr(1, Range("M" & i).Value, "vodka", vbTextCompare) Then
Range("M" & i).entirerow.delete
End If
Next i
End Sub
I would use a slightly different approach, with the Like and with Select Case - this will give you more versatility in the future if you would want to expand it to more types of drinks.
Sub FindDrink()
Dim lRow As Long
Dim i As Long
Dim sht As Worksheet
' always set your sht, modify to your sheet name
Set sht = ThisWorkbook.Sheets("Sheet1")
lRow = sht.Cells(sht.Rows.Count, "M").End(xlUp).Row
For i = lRow To 2 Step -1
Select Case True
Case (sht.Cells(i, "M").Value Like "*beer*") Or (sht.Cells(i, "M").Value Like "*water*") Or (sht.Cells(i, "M").Value Like "*vodka*")
Range("M" & i).EntireRow.Delete
Case Else
' if you decide to do other things in the future for other values
End Select
Next i
End Sub
use excel built in filtering functions for the maximum speed
Autofilter
Option Explicit
Sub main()
Dim keysToErase As Variant, key As Variant
keysToErase = Array("water", "beer", "vodka") '<--| list your keywords to delete matching column "M" rows with
Application.DisplayAlerts = False '<--| prevent alerts dialog box from appearing at every rows deletion
With Workbooks("test").Worksheets("SOVI").Range("A1").CurrentRegion '<--| this gets the range of all contiguous cells to "A1"
For Each key In keysToErase '<--| loop through keys
.AutoFilter field:=13, Criteria1:="*" & key & "*" '<--| filter column "M" with key
If Application.WorksheetFunction.Subtotal(103, .Cells.Resize(, 1)) > 1 Then .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Delete '<--| delete filtered cells, if any
Next key
.Parent.ShowAllData '<--| .. show all rows back...
End With
Application.DisplayAlerts = True '<--| allow alerts dialog box back
End Sub
AdvancedFilter
Option Explicit
Sub main2()
Application.DisplayAlerts = False '<--| prevent alerts dialog box from appearing at every rows deletion
With Workbooks("test").Worksheets("SOVI").Range("A1").CurrentRegion '<--| this gets the range of all contiguous cells to "A1"
.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=.Parent.Range("U1:U4") '<--| this filters on all keys you placed in cells "U2:U4" with cell "U1" with wanted data header
If Application.WorksheetFunction.Subtotal(103, .Cells.Resize(, 1)) > 1 Then .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Delete '<--| delete filtered cells, if any
.Parent.ShowAllData '<--| .. show all rows back...
End With
Application.DisplayAlerts = True '<--| allow alerts dialog box back
End Sub
Try with Below code
Sub test()
Application.DisplayAlerts = False
Dim lastrow As Long
Dim i As Long
Dim currentrng As Range
lastrow = Range("M" & Rows.Count).End(xlUp).Row
For i = lastrow To 2 Step -1
Set currentrng = Range("M" & i)
If ((currentrng Like "*water*") Or (currentrng Like "*beer*") Or (currentrng Like "*vodka*")) Then
currentrng.EntireRow.Delete shift:=xlUp
End If
Next i
Application.DisplayAlerts = True
End Sub

Copy data to another workbook and filter to different sheets based on criteria

I have written the below script to copy a range of data from one sheet to another workbook based on a set of criteria. I now need to add an extra piece to filter this acceptable data to different sheets named after the values in column G and if the value doesn't already exist to create the sheet named after the value. For example if column G value = JULA then to copy this to sheet JULA however if this doesn't already exist then to create and copy.
Private Sub cmdArchive_click()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim LastRow As Integer, i As Integer, erow As Integer
iForm = ("\\Insurance\It\FileData\Computers\Release Note\Collated Release Records\Master.xlsx")
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 3 To LastRow
If Cells(i, 1) <> "" And Cells(i, 9) = "" And Cells(i, 9) = "" Then
Range(Cells(i, 1), Cells(i, 4)).Select
Selection.Copy
workbooks.Open Filename:=iForm
Worksheets("Scheduled Forms").Select
erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Cells(erow, 1).Select
ActiveSheet.Paste
ActiveWorkbook.Save
ActiveWorkbook.Close
Application.CutCopyMode = False
End If
Next i
MsgBox ("iForms have been archived, please clear the Team Release notes ready for the next implimentation window"), vbInformation + vbOKOnly, "Complete!"
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Thank you in advance.

Excel Add Sheet or Overwrite if Exists

In excel I have a macro that converts all of columns of an active sheet into an new sheet called "MasterList"
My problem is when I rerun that macro I get an error saying "That name is already taken." Try a different one.
I need my macro to overwrite MaterList sheet if it already exists.
Here is my code:
Sub ToArrayAndBack()
Dim arr As Variant, lLoop1 As Long, lLoop2 As Long
Dim arr2 As Variant, lIndex As Long
'turn off updates to speed up code execution
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
.DisplayAlerts = False
End With
ReDim arr2(ActiveSheet.UsedRange.Cells.Count - ActiveSheet.UsedRange.SpecialCells(xlCellTypeBlanks).Count)
arr = ActiveSheet.UsedRange.Value
For lLoop1 = LBound(arr, 1) To UBound(arr, 1)
For lLoop2 = LBound(arr, 2) To UBound(arr, 2)
If Len(Trim(arr(lLoop1, lLoop2))) > 0 Then
arr2(lIndex) = arr(lLoop1, lLoop2)
lIndex = lIndex + 1
End If
Next
Next
Sheets.Add.Name = "MasterList"
Range("A1").Resize(, lIndex + 1).Value = arr2
Range("A1").Resize(, lIndex + 1).Copy
Range("A2").Resize(lIndex + 1).PasteSpecial Transpose:=True
Rows(1).Delete
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayAlerts = True
End With
End Sub
You can put the sheet creation between on error resume and on error goto 0. The other solution is to loop through the workbook sheets collection and check if a sheet with that name exists.
Solution 1:
On Error Resume Next
Sheets.Add.Name = "MasterList"
On Error GoTo 0
Solution 2:
Dim ws As Worksheet
Dim found As Boolean
found = False
For Each ws In ThisWorkbook.Sheets
If ws.Name = "MasterList" Then
found = True
Exit For
EndIf
Next
If Not found Then
Sheets.Add.Name = "MasterList"
EndIf
To avoid relying on the fact that MasterList is active:
Set ws = ThisWorkbook.Sheets("MasterList")
With ws
.Range("A1").Resize(, lIndex + 1).Value = arr2
.Range("A1").Resize(, lIndex + 1).Copy
.Range("A2").Resize(lIndex + 1).PasteSpecial Transpose:=True
.Rows(1).Delete
End With