I have a workbook with 10+ sheets, with hundreds of thousands of values in each (125k sheet1, 240k sheet 2, 400k sheet 3, etc.) I am trimming down the sheets by keeping every thousandth or so point in each sheet.
I have been unable to get the code to finish trimming data on the first sheet. The code has run for well over an hour without finishing the first sheet. I've tried with smaller data sets as well (~1000 points in 5 sheets), but the macro only successfully trims points on the first sheet. The other sheets are not modified
Below is the code I'm using to delete an interval of rows; it is the most customizable way to delete rows I could find (which is exactly what i'm looking for: customization/simplicity
lastRow = Application.ActiveSheet.UsedRange.Rows.Count
For i = 2 To lastRow Step 1 'Interval of rows to delete
Range(Rows(i), Rows(i + 997)).Delete Shift:=xlUp
Next i
The code for this specific task is inserted into a modified version of a codes found in this question *credit to those who originally wrote them
Question: Excel VBA Performance - 1 million rows - Delete rows containing a value, in less than 1 min
Here's Helper Functions paul bica used in his code
Public Sub FastWB(Optional ByVal opt As Boolean = True)
With Application
.Calculation = IIf(opt, xlCalculationManual, xlCalculationAutomatic)
.DisplayAlerts = Not opt
.DisplayStatusBar = Not opt
.EnableAnimations = Not opt
.EnableEvents = Not opt
.ScreenUpdating = Not opt
End With
FastWS , opt
End Sub
Public Sub FastWS(Optional ByVal ws As Worksheet = Nothing, _
Optional ByVal opt As Boolean = True)
If ws Is Nothing Then
For Each ws In Application.ActiveWorkbook.Sheets
EnableWS ws, opt
Next
Else
EnableWS ws, opt
End If
End Sub
Private Sub EnableWS(ByVal ws As Worksheet, ByVal opt As Boolean)
With ws
.DisplayPageBreaks = False
.EnableCalculation = Not opt
.EnableFormatConditionsCalculation = Not opt
.EnablePivotTable = Not opt
End With
End Sub
A nifty little code for generating a test set by marko2049:
Sub DevelopTest()
Dim index As Long
FastWB True
ActiveSheet.UsedRange.Clear
For index = 1 To 1000000 '1 million test
ActiveSheet.Cells(index, 1).Value = index
If (index Mod 10) = 0 Then
ActiveSheet.Cells(index, 2).Value = "Test String"
Else
ActiveSheet.Cells(index, 2).Value = "Blah Blah Blah"
End If
Next index
Application.StatusBar = ""
FastWB False
End Sub
After generating a test set and copying it to several sheets, I ran a modified version of the code below
The main body of the code was made by user marko5049
Sub DeleteRowFast()
Dim curWorksheet As Worksheet 'Current worksheet vairable
Dim rangeSelection As Range 'Selected range
Dim startBadVals As Long 'Start of the unwanted values
Dim endBadVals As Long 'End of the unwanted values
Dim strtTime As Double 'Timer variable
Dim lastRow As Long 'Last Row variable
Dim lastColumn As Long 'Last column variable
Dim indexCell As Range 'Index range start
Dim sortRange As Range 'The range which the sort is applied to
Dim currRow As Range 'Current Row index for the for loop
Dim cell As Range 'Current cell for use in the for loop
On Error GoTo Err
Set rangeSelection = Application.InputBox("Select the (N=) range to be checked", "Get Range", Type:=8) 'Get the desired range from the user
Err.Clear
M1 = MsgBox("This is recommended for large files (50,000 or more entries)", vbYesNo, "Enable Fast Workbook?") 'Prompt the user with an option to enable Fast Workbook, roughly 150% performace gains... Recommended for incredibly large files
Select Case M1
Case vbYes
FastWB True 'Enable fast workbook
Case vbNo
FastWB False 'Disable fast workbook
End Select
strtTime = Timer 'Begin the timer
Set curWorksheet = ActiveSheet
lastRow = CLng(rangeSelection.SpecialCells(xlCellTypeLastCell).Row)
lastColumn = curWorksheet.Cells(1, 16384).End(xlToLeft).Column
Set indexCell = curWorksheet.Cells(1, 1)
On Error Resume Next
If rangeSelection.Rows.Count > 1 Then 'Check if there is anything to do
lastVisRow = rangeSelection.Rows.Count
Set sortRange = curWorksheet.Range(indexCell, curWorksheet.Cells(curWorksheet.Rows(lastRow).Row, 16384).End(xlToLeft)) 'Set the sort range
sortRange.Sort Key1:=rangeSelection.Cells(1, 1), Order1:=xlAscending, Header:=xlNo 'Sort by values, lowest to highest
startBadVals = rangeSelection.Find(What:="Test String", LookAt:=xlWhole, MatchCase:=False).Row
endBadVals = rangeSelection.Find(What:="Test String", LookAt:=xlWhole, SearchDirection:=xlPrevious, MatchCase:=False).Row
curWorksheet.Range(curWorksheet.Rows(startBadVals), curWorksheet.Rows(endBadVals)).EntireRow.Delete 'Delete uneeded rows, deleteing in continuous range blocks is quick than seperated or individual deletions.
sortRange.Sort Key1:=indexCell, Order1:=xlAscending, Header:=xlNo 'Sort by index instead of values, lowest to highest
End If
Application.StatusBar = "" 'Reset the status bar
FastWB False 'Disable fast workbook
MsgBox CStr(Round(Timer - strtTime, 2)) & "s" 'Display duration of task
Err:
Exit Sub
End Sub
I've modified the above code as follows
Sub DeleteRowFastMod()
Dim lastRow As Long
Dim i As Long
Dim ws As Worksheet
Dim wb As Workbook
Set wb = Application.ActiveWorkbook
On Error GoTo Err
'Get the desired range from the user
Err.Clear
FastWB True 'Enable fast workbook
strtTime = Timer 'Begin the timer
On Error Resume Next
For Each ws In wb.Worksheets(1) 'Loop through sheets in workbook
ws.Activate
lastRow = Application.ActiveSheet.UsedRange.Rows.Count
If lastRow > 1 Then 'Check if there is anything to do
For i = 2 To lastRow Step 1 'Interval of rows to delete
Range(Rows(i), Rows(i + 997)).Delete Shift:=xlUp
Next i
End If
Next
Application.StatusBar = "" 'Reset the status bar
FastWB False 'Disable fast workbook
MsgBox CStr(Round(Timer - strtTime, 2)) & "s" 'Display duration of task
Err:
Exit Sub
End Sub
I am not sure how to further modify this code to run on each sheet in the workbook in a timely manner.
Thanks in advance for any guidance