Editing code to stop user from jumping from sheet to sheet - vba

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

Related

Removing blank columns/rows in VBA as part of csv save

I am using the following VBA code to save each individual sheet in a .xlsx workbook into a .csv file.
Whilst the code is working well I would like to adapt the VBA code so blank columns & rows are removed from the .csv files which are being created.
Existing VBA Code:
Public Sub SaveWorksheetsAsCsv()
Dim xWs As Worksheet
Dim xDir As String
Dim folder As FileDialog
Set folder = Application.FileDialog(msoFileDialogFolderPicker)
If folder.Show <> -1 Then Exit Sub
xDir = folder.SelectedItems(1)
For Each xWs In Application.ActiveWorkbook.Worksheets
xWs.SaveAs xDir & "\" & xWs.Name, xlCSV
Next
End Sub
To remove blank rows & columns I was able to get the below JavaScript working in a .hta application, but would like to integrate this same functionality into the above VBA code.
//Remove all blank rows
for(var i = usedRng.Rows.Count; i > 0; i--){
if( xlApp.CountA(usedRng.Rows(i)) == 0 ) usedRng.Rows(i).Delete();
}
//Remove all blank columns
for(var i = usedRng.Columns.Count; i > 0; i--){
if( xlApp.CountA(usedRng.Columns(i)) == 0 ) usedRng.Columns(i).Delete();
}
How can I integrate this row/column removal code into VBA?
Use below sub-routine to delete empty row/column in the spreadsheet
Sub RemoveEmptyRowColumn()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
CalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
ActiveSheet.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
Firstrow = ActiveSheet.UsedRange.Cells(1).Row
Lastrow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
FirstColumn = ActiveSheet.UsedRange.Cells(1).Column
LastColumn = ActiveSheet.UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count).Column
'------------------
' Delete Empty Rows
'------------------
For Lrow = Lastrow To Firstrow Step -1
For LColumn = LastColumn To FirstColumn Step -1
With ActiveSheet.Cells(Lrow, LColumn)
If Not IsError(.Value) Then
If .Value = "" Then
DeleteRow = "Yes"
Else
DeleteRow = "No"
Exit For
End If
End If
End With
Next LColumn
If DeleteRow = "Yes" Then
ActiveSheet.Cells(Lrow, LColumn + 1).EntireRow.Delete
End If
Next Lrow
'---------------------
' Delete Empty Columns
'---------------------
For LColumn = LastColumn To FirstColumn Step -1
For Lrow = Lastrow To Firstrow Step -1
With ActiveSheet.Cells(Lrow, LColumn)
If Not IsError(.Value) Then
If .Value = "" Then
DeleteColumn = "Yes"
Else
DeleteColumn = "No"
Exit For
End If
End If
End With
Next Lrow
If DeleteColumn = "Yes" Then
ActiveSheet.Cells(Lrow + 1, LColumn).EntireColumn.Delete
End If
Next LColumn
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
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

if cell contains specific text, copy whole row

I'm trying to create a macro that does this:
Check the values from a small list (I've used an array)
Go in a worksheet and for every row that contains one of the values of the array copy the entire row in another worksheet.
I've mixed other macros to create one but I got one problem, the macro check the value on the array and copies all the rows in my worksheet but every time it doesn't copy the first row found: ex, if row that contain "abl" are: 100,200 and 300, the macro just copy 200 and 300 ignoring 100.
This is my macro
Sub Test_339_1()
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
Dim nam(1 To 7) As String, cel As Range, rng As Range
i = 1
Set rng = Worksheets("Ctr 339").Range("V4:V10")
For Each cel In rng
nam(i) = cel.Value
i = i + 1
Next cel
For i = 1 To 7
For Each cell In Sheets("FB03").Range("E:E")
If cell.Value = nam(i) Then
matchRow = cell.Row
Rows(matchRow & ":" & matchRow).Copy
Sheets("Test_macro").Select
ActiveSheet.Rows(matchRow).Select
ActiveSheet.Paste
Sheets("FB03").Select
End If
Next
Sheets("Test_macro").Select
Next i
Sheets("Test_macro").Select
On Error Resume Next
Range("A1:A50000").Select
Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End Sub
Try this refactored code:
Sub Test_339_1()
Dim nam(1 To 7) As String, cel As Range, lastrow As Long
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
nam = Worksheets("Ctr 339").Range("V4:V10").Value
lastrow = Sheets("FB03").Cells(Sheets("FB03").Rows.Count, "E").End(xlUp).Row
For Each cell In Sheets("FB03").Range("E1:E" & lastrow)
For i = 1 To 7
If cell.Value = nam(i) Then
matchRow = cell.Row
Sheets("FB03").Rows(matchRow).Copy Sheets("Test_macro").Rows(Sheets("Test_macro").Cells(Sheets("Test_macro").Rows.Count, "E").End(xlUp).Row + 1)
Exit For
End If
Next i
Next cell
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End Sub
It should be quicker, It will not loop over 7 million times.
AutoFilter() should speed things up quite a bit:
Option Explicit
Sub Test_339_1()
Dim nam As Variant
nam = Application.Transpose(Worksheets("Ctr 339").Range("V4:V10").Value)
With Sheets("FB03")
With .Range("E1", .Cells(.Rows.Count, "E").End(xlUp))
.AutoFilter Field:=1, Criteria1:=nam, Operator:=xlFilterValues '<--| filter referenced range on its 3rd column (i.e. "State") with 1
If Application.WorksheetFunction.Subtotal(103, .Cells) > 1 Then '<--| if any filterd cells other than header
With .Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible)
.EntireRow.Copy Sheets("Test_macro").Cells(.Cells(1, 1).Row,1)
End With
End If
End With
.AutoFilterMode = False
End With
End Sub
you only need row 1 to be a header one, i.e. actual data to be filtered begin from row 2 downwards
also this pastes values in target sheet from cell A1 downwards without blank rows. Should original row sequence be respected, it can be done

VBA Unique word sort

Trying to find unique names in column B, and copy any rows with said name to new worksheet.
i.e. Alex clocks in twice this week he will fill two rows with data, I want to move his two rows of data to their own worksheet. Fred only clocks in once and creates 1 row of data, I want to move his row to a new worksheet.
Problem, it is copying row 2 to multiple of the new worksheets
link to my file: https://docs.google.com/spreadsheets/d/1JZla8ySwEotn91m8trh2_2fNLBNak-of98HQJ0YCP_0/edit?usp=sharing
code i'm using so far:
Sub Copy_To_Worksheets()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
'and the header of the first column, D is the last column in the filter range.
'You can also add the sheet name to the code like this :
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A2:E" & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new worksheet"
Exit Sub
End If
'This example filters on the first column in the range(change the field if needed)
'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
FieldNum = 2
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Change ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Add a worksheet to copy the a unique list and add the CriteriaRange
Set ws2 = Worksheets.Add
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A1"), Unique:=True
'loop through the unique list in ws2 and filter/copy to a new sheet
Lrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A1:A" & Lrow)
'Filter the range
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Check if there are no more then 8192 areas(limit of areas)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "There are more than 8192 areas for the value : " & cell.Value _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Split in worksheets"
Else
'Add a new worksheet
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = cell.Value
If Err.Number > 0 Then
ErrNum = ErrNum + 1
WSNew.Name = "Error_" & Format(ErrNum, "0000")
Err.Clear
End If
On Error GoTo 0
'Copy the visible data to the new worksheet
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 will copy the columnwidth in Excel 2000 and higher
' Remove this line if you use Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
End If
'Show all data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
'Delete the ws2 sheet
On Error Resume Next
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
On Error GoTo 0
End With
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
& vbNewLine & "There are characters in the name that are not allowed" _
& vbNewLine & "in a sheet name or the worksheet already exist."
End If
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
I would likely do it this way, but this would need more error checking.
Option Explicit
Sub MovePeeps()
Dim emp As New Collection
Dim ws, tmpWs, tw As Worksheet
Dim wb As Workbook
Dim empExist As Boolean
Dim i, j, k, m As Integer
Set wb = ThisWorkbook
Set ws = wb.ActiveSheet
empExist = False
'get unique employee names into the emp collection
'cycle through the used range - i= column of names
For i = 2 To ws.UsedRange.Rows.Count
'cycle through all peopel in the emp collection
For j = 1 To emp.Count
'check if person in cell = person in emp collection
If ws.Cells(i, 2) = emp(j) Then
empExist = True
Exit For
End If
Next j
'if person is in emp collection already reset empExist and exit loop without adding again
If empExist = True Then
empExist = False
Exit For
End If
'otherwise add that person to the collection
emp.Add ws.Cells(i, 2)
Next i
'create a worksheet named after each item in the emp collection
For i = 1 To emp.Count
wb.Worksheets.Add After:=wb.Worksheets(wb.Worksheets.Count)
Set tmpWs = wb.Worksheets(wb.Worksheets.Count)
tmpWs.Name = emp(i)
'add header row to each sheet
ws.Cells(1, 2).EntireRow.Copy Destination:=tmpWs.Cells(1, 1)
Next i
'copy all data to the new sheets
m = 1
For j = 1 To emp.Count
For Each tw In wb.Worksheets
'if the worksheet (tw) is the same name as the person in emp(j) then set the tmpWS variable
If tw.Name = emp(j) Then
Set tmpWs = tw
Exit For
End If
Next tw
For i = 2 To ws.UsedRange.Rows.Count
If ws.Cells(i, 2) = emp(j) Then
'find blank row on the sheet we are copying to
Do While tmpWs.Cells(m, 2) <> ""
m = m + 1
Loop
'copy the row to the tmpWS
ws.Cells(i, 2).EntireRow.Copy Destination:=tmpWs.Cells(m, 1)
End If
Next i
'reset our blank row counter.
m = 1
Next j
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