Invalid qualifier error when deleting rows - excel

I'm using a macro that is running into an error
Invalid qualifier
pointing to the i variable.
Sub Macro6()
Dim last As Long
Dim i As Long
With ActiveSheet
last = .Cells(.Rows.Count, 1).End(xlDown).Row
For i = last To 1 Step -1
If .Cells(i, 1).Value Like "X" Then
.Cells(i.End(xlDown), 1).EntireRow.Delete
End If
Next i
This macro is supposed to identify cell with value "X" (that will be located at the end of column A) and then delete all rows below that are empty.

Delete Below String
Application.Match
If you are expecting one occurrence of the string or you're after the first occurrence, then the safer and more efficient choice is using Application.Match.
Sub DeleteBelowFirst()
' Uses 'Application.Match'.
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
If ws.AutoFilterMode Then ws.AutoFilterMode = False (optionally)
Dim rg As Range: Set rg = ws.UsedRange
DeleteBelowFirstString rg, 1, "x" ' , True ' True would keep the found row
End Sub
Sub DeleteBelowFirstString( _
ByVal rg As Range, _
ByVal ColumnIndex As Long, _
ByVal CriteriaString As String, _
Optional ByVal ExcludeFoundRow As Boolean = False)
' If the worksheet is filtered, only the filtered (visible) rows will be deleted.
Const ProcName As String = "DeleteBelowFirstString"
Dim crg As Range: Set crg = rg.Columns(ColumnIndex)
Dim rIndex As Variant: rIndex = Application.Match(CriteriaString, crg, 0)
If IsError(rIndex) Then
MsgBox "Value not found.", vbExclamation, ProcName
Exit Sub
End If
Dim rCount As Long: rCount = rg.Rows.Count
Dim rOffset As Long: rOffset = rIndex - 1
If ExcludeFoundRow Then
rOffset = rOffset + 1
If rCount = rOffset Then
MsgBox "There's nothing below.", vbExclamation, ProcName
Exit Sub
End If
End If
Dim drg As Range: Set drg = rg.Resize(rCount - rOffset).Offset(rOffset)
Debug.Print ProcName & ": " & drg.Address & " deleted."
drg.Delete xlShiftUp
End Sub
Range.Find
If you're after the last occurrence, then Application.Match does not work and you could e.g. use Range.Find with its limitations. It will also work for a single occurrence.
Sub DeleteBelowLast()
' Uses 'Range.Find'.
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
If ws.AutoFilterMode Then ws.AutoFilterMode = False (mandatory)
Dim rg As Range: Set rg = ws.UsedRange
DeleteBelowLastString rg, 1, "x" ' , True ' True would keep the found row
End Sub
Sub DeleteBelowLastString( _
ByVal rg As Range, _
ByVal ColumnIndex As Long, _
ByVal CriteriaString As String, _
Optional ByVal ExcludeFoundRow As Boolean = False)
' Make sure the worksheet is not filtered or the Find method will fail.
Const ProcName As String = "DeleteBelowLastString"
Dim crg As Range: Set crg = rg.Columns(ColumnIndex)
' If the column contains formulas, instead of 'xlFormulas', use 'xlValues'
' and additionally make sure that no rows are hidden
' or the Find method will fail (hidden rows don't affect 'xlFormulas').
Dim fCell As Range: Set fCell = crg.Find( _
What:=CriteriaString, After:=crg.Cells(1), LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchDirection:=xlPrevious) ' last occurrence
If fCell Is Nothing Then
MsgBox "Value not found.", vbExclamation, ProcName
Exit Sub
End If
Dim rCount As Long: rCount = rg.Rows.Count
Dim rOffset As Long: rOffset = fCell.Row - rg.Row
If ExcludeFoundRow Then
rOffset = rOffset + 1
If rCount = rOffset Then
MsgBox "There's nothing below.", vbExclamation, ProcName
Exit Sub
End If
End If
Dim drg As Range: Set drg = rg.Resize(rCount - rOffset).Offset(rOffset)
Debug.Print ProcName & ": " & drg.Address & " deleted."
drg.Delete xlShiftUp
End Sub
Note that both methods support wild characters.

I'd suggest you skip the loop, and use Range.Find instead.
Sub DeleteAllAfterX()
With ActiveSheet
Dim rng As Range
Set rng = .Range("A:A").Find(What:="X", LookIn:=xlValues, Lookat:=xlWhole)
If Not rng Is Nothing Then
.Rows(rng.Row & ":" & .Rows.Count).ClearContents
End If
End With
End Sub

Related

Function for finding the row of a cell with a specific text

If I want to find the row number of a cell in column A with the text containing the string "Total Labor", how can I do that?
Another is how can I find the position of the cell containing that text if it can be in any column and row?
This is what I have, but it returns as an Empty.
TotalLaborPos is defined as a Variant.
lastrow = Range("A11").End(xlDown)
TotalLaborPos.Value = ActiveSheet.Match("Total Labor", Range("A11:A" & lastrow), 0)
It's Application.Match not ActiveSheet.Match
If it can be in any column/row then use Find()
E.g.
Dim f As Range
Set f = ActiveSheet.Cells.Find("Total Labor",lookat:=xlWhole,lookin:=xlValues)
If not f is nothing then
debug.print "found", f.address
end if
The Worksheet Row of the First Match in a Column
Option Explicit
Sub GetFirstMatchInColumnRowTEST()
Const First As String = "A11"
Const StringToMatch As String = "Total Labor"
Dim ws As Worksheet: Set ws = ActiveSheet
Dim fCell As Range: Set fCell = ws.Range(First)
Dim mRow As Long: mRow = GetFirstMatchInColumnRow(fCell, StringToMatch)
If mRow = 0 Then Exit Sub ' not found
' Continue with code...
Debug.Print ws.Cells(mRow, fCell.Column).Address(0, 0)
End Sub
Function GetFirstMatchInColumnRow( _
ByVal rg As Range, _
ByVal StringToMatch As String) _
As Long
If rg Is Nothing Then Exit Function ' no range
' Create a reference to the Search (Column) Range ('srg').
Dim wsrCount As Long: wsrCount = rg.Worksheet.Rows.Count
Dim fRow As Long: fRow = rg.Row
Dim srCount As Long: srCount = wsrCount - fRow + 1
Dim srg As Range: Set srg = rg.Cells(1).Resize(srCount)
' 1.) Using 'Range.Find'.
Dim mCell As Range: Set mCell = srg.Find(StringToMatch, _
srg.Cells(srg.Cells.Count), xlFormulas, xlWhole)
If mCell Is Nothing Then Exit Function ' not found
GetFirstMatchInColumnRow = mCell.Row
' ' 2.) Using 'Application.Match' '
' Dim rIndex As Variant: rIndex = Application.Match(StringToMatch, srg, 0)
' If IsError(rIndex) Then Exit Function ' not found
'
' GetFirstMatchInColumnRow = srg.Cells(rIndex).Row
End Function

Matching the Three Criteria and Copy Paste the Data

Below code match the string in the specific range (this range contains Headers) if finds then copy the whole column and paste into Sheet2.
I want to add two more condition in below code that are:
Dim FindValue2 As String
Dim FindValue3 As String
FindValue2 = shSummary.Range("A2").Value
FindValue3 = shSummary.Range("B2").Value
and match in Sheet1 Column A for FindValue3 and Column F for FindValue2 after matching these 3 criteria then copy and paste the data.
Your help will be much appreciated.
Sub find()
Dim foundRng As Range
Dim FindValue As String
Dim lastRow As Long
Set shData = Worksheets("Sheet1")
Set shSummary = Worksheets("Sheet2")
FindValue = shSummary.Range("C2")
Set foundRng = shData.Range("G1:Z1").find(FindValue)
With shData
lastRow = .Cells(.Rows.Count, foundRng.Column).End(xlUp).Row
End With
shData.Rows("2:" & lastRow).Columns(foundRng.Column).Copy shSummary.Range("I3")
End Sub
Apply a filter to columns A and F then copy the visible cells.
Option Explicit
Sub Find3()
Dim wb As Workbook, wsData As Worksheet, wsSummary As Worksheet
Dim rngFound As Range, rngData As Range, rngCopy As Range
Dim FindValue As String, FilterA As String, FilterF As String
Dim lastRow As Long, c As Long
Set wb = ThisWorkbook
Set wsData = wb.Worksheets("Sheet1")
wsData.AutoFilterMode = False
Set wsSummary = wb.Worksheets("Sheet2")
With wsSummary
FindValue = .Range("B2")
FilterA = .Range("C2")
FilterF = .Range("A2")
End With
Set rngFound = wsData.Range("G1:Z1").find(FindValue)
If rngFound Is Nothing Then
MsgBox "'" & FindValue & "' not found", vbCritical
Exit Sub
End If
' column matching FindValue
c = rngFound.Column
lastRow = wsData.Cells(Rows.Count, c).End(xlUp).Row
If lastRow = 1 Then
MsgBox "No data in column " & c, vbCritical
Exit Sub
End If
' filter data on colA and F
With wsData
Set rngData = .Cells(2, c).Resize(lastRow - 1)
.UsedRange.AutoFilter
.UsedRange.AutoFilter Field:=1, Criteria1:=FilterA
.UsedRange.AutoFilter Field:=6, Criteria1:=FilterF
' data to copy
On Error Resume Next
Set rngCopy = rngData.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
' copy data
If rngCopy Is Nothing Then
MsgBox "No data to copy from column " & c, vbCritical
.AutoFilterMode = False
Exit Sub
Else
rngCopy.Copy wsSummary.Range("I3")
End If
.AutoFilterMode = False
End With
MsgBox "Done"
End Sub
Copy Data Columns to Another Worksheet
Adjust the values in the constants section.
Delete (out-comment) the Debug.Print lines when done testing.
Option Explicit
Sub ExportDataColumns()
Const sName As String = "Sheet1"
Const sHeadersAddress As String = "G1:Z1"
Const dName As String = "Sheet2"
Const dReadList As String = "A2,B2,C2"
Const dWriteList As String = "F3,A3,I3"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim wsrCount As Long: wsrCount = sws.Rows.Count
Dim shrg As Range: Set shrg = sws.Range(sHeadersAddress)
Debug.Print "Source Header Range: " & shrg.Address(0, 0)
Dim sfRow As Long: sfRow = shrg.Row + 1 ' first row below the headers
Debug.Print "Source First Row: " & sfRow
If sfRow >= wsrCount Then Exit Sub
Dim slRow As Long: slRow = GetLastRow(shrg)
Debug.Print "Source Last Row: " & slRow
If slRow < sfRow Then Exit Sub
Dim sdrg As Range
Set sdrg = shrg.Resize(slRow - sfRow + 1).Offset(1)
Debug.Print "Source Data Range: " & sdrg.Address(0, 0)
Dim dRead() As String: dRead = Split(dReadList, ",")
Dim dWrite() As String: dWrite = Split(dWriteList, ",")
Dim dUpper As Long: dUpper = UBound(dRead)
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim srg As Range
Dim drg As Range
Dim dcrg As Range
Dim srCount As Long
Dim n As Long
For n = 0 To dUpper
Debug.Print "Item " & n + 1
Dim scIndex As Variant
scIndex = Application.Match(dws.Range(dRead(n)).Value, shrg, 0)
If IsNumeric(scIndex) Then
Set srg = sdrg.Columns(scIndex)
Debug.Print "Source Range: " & srg.Address(0, 0)
srCount = srg.Rows.Count
Set drg = dws.Range(dWrite(n)).Resize(srCount)
Debug.Print "Destination Range: " & drg.Address(0, 0)
drg.Value = srg.Value
Set dcrg = drg.Resize(wsrCount - drg.Row - srCount + 1) _
.Offset(srCount)
Debug.Print "Destination Clear Range: " & dcrg.Address(0, 0)
dcrg.ClearContents
End If
Next n
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the worksheet row number of the last non-empty row
' in the range from the first row of a range ('rg')
' through the same sized bottom-most row of the worksheet.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetLastRow( _
ByVal rg As Range) _
As Long
If rg Is Nothing Then Exit Function
Dim lCell As Range
With rg.Rows(1)
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
End With
If lCell Is Nothing Then Exit Function
GetLastRow = lCell.Row
End Function

Combine data from multiple worksheets to one sheet on key word from column

im sorry for making similar question but im run into a problem, bcs i don t know very good VBA coding...
I found many similar questions, and i found a code that i can apply to my needs.
I found code here But i don't know how to edit that code so that he can work in my Workbook. I have workbook with 35 worksheets, all with same format, values are in columns "A:F", in column "E" i have text "On Stock" and "Sent", i want all rows from all worksheets that have "On Stock" value in column "E" to be copied into one worksheet named "Blanko List". I tried to edit code myself, but it can t run, nothing happens. Thanks in advance.
Edited code
Sub CommandButton4_Click()
Dim wM As Worksheet, ws As Worksheet
Dim r As Long, lr As Long, nr As Long, y As Long
Dim c As Range, firstaddress As String
Application.ScreenUpdating = False
Set wM = Sheets("Blanko List")
lr = wM.Cells.Find("*", , xlValues, xlWhole, xlByRows, xlPrevious, False).Row
If lr > 1 Then wM.Range("A2:G" & lr).ClearContents
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Blanko List" Then
y = 0
On Error Resume Next
y = Application.CountIf(ws.Columns(7), "On Stock")
On Error GoTo 0
If y > 1 Then
firstaddress = ""
With ws.Columns(7)
Set c = .Find("On Stock", LookIn:=xlValues, LookAt:=xlWhole)
If Not c Is Nothing Then
firstaddress = c.Address
Do
nr = wM.Range("G" & Rows.Count).End(xlUp).Offset(1).Row
ws.Range("A" & c.Row & ":G" & c.Row).Copy wM.Range("A" & nr)
Application.CutCopyMode = False
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstaddress
End If
End With
End If
End If
Next ws
wM.Activate
Application.ScreenUpdating = True
''''
Original code:
Option Explicit
Sub GetYes()
Dim wM As Worksheet, ws As Worksheet
Dim r As Long, lr As Long, nr As Long, y As Long
Dim c As Range, firstaddress As String
Application.ScreenUpdating = False
Set wM = Sheets("Master")
lr = wM.Cells.Find("*", , xlValues, xlWhole, xlByRows, xlPrevious, False).Row
If lr > 1 Then wM.Range("A2:G" & lr).ClearContents
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Master" Then
y = 0
On Error Resume Next
y = Application.CountIf(ws.Columns(7), "Yes")
On Error GoTo 0
If y > 1 Then
firstaddress = ""
With ws.Columns(7)
Set c = .Find("Yes", LookIn:=xlValues, LookAt:=xlWhole)
If Not c Is Nothing Then
firstaddress = c.Address
Do
nr = wM.Range("G" & Rows.Count).End(xlUp).Offset(1).Row
ws.Range("A" & c.Row & ":G" & c.Row).Copy wM.Range("A" & nr)
Application.CutCopyMode = False
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstaddress
End If
End With
End If
End If
Next ws
wM.Activate
Application.ScreenUpdating = True
End Sub
Copy Criteria Rows
Option Explicit
Sub CopyCriteriaRows()
' Source
Const sCols As String = "A:F"
Const sfRow As Long = 2
Const scCol As Long = 5
Const sCriteria As String = "On Stock"
' Destination
Const dName As String = "Blanco List"
Const dFirst As String = "A2"
' Exceptions
Const ExceptionsList As String = "Blanco List" ' add more
Const ListSeparator As String = ","
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Write the names of the worksheets to be 'processed' to an array.
Dim wsNames As Variant
wsNames = ArrWorksheetNames(wb, ExceptionsList, ListSeparator)
If IsEmpty(wsNames) Then Exit Sub ' no worksheet found
' Create a reference to the first destination row range.
' Note that the number of columns is equal in source and destination.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim cCount As Long: cCount = dws.Columns(sCols).Columns.Count
Dim drrg As Range: Set drrg = dws.Range(dFirst).Resize(, cCount)
Dim sws As Worksheet ' Source Worksheet
Dim srg As Range ' Source Range
Dim sfrrg As Range ' Source First Row Range
Dim drg As Range ' Destination Range
Dim Data As Variant ' Data Array
Dim cValue As Variant ' Current Value
Dim dr As Long ' Destination Row Counter
Dim sr As Long ' Source Row Counter
Dim c As Long ' Column Counter
For Each sws In wb.Worksheets(wsNames)
' Create a reference to the current Source First Row Range.
Set sfrrg = sws.Columns(sCols).Rows(sfRow)
Set srg = Nothing
' Create a reference to the current Source Range.
Set srg = RefColumns(sfrrg)
If Not srg Is Nothing Then ' the current Source Range is not empty
' Write the values from the current Source Range to the Data Array.
Data = GetRange(srg)
' Write the matches to the top of the Data Array. The size
' of the array stays the same but 'dr' is used: to track
' the number of, to move, and finally, to write (to the worksheet)
' the 'destination' values.
dr = 0
For sr = 1 To UBound(Data, 1)
cValue = Data(sr, scCol)
If StrComp(CStr(cValue), sCriteria, vbTextCompare) = 0 Then
dr = dr + 1
For c = 1 To cCount
Data(dr, c) = Data(sr, c)
Next c
End If
Next sr
If dr > 0 Then ' there have been matches
' Create a reference to the Destination Range.
Set drg = drrg.Resize(dr)
' Write only the 'destination' values (dr) from
' the Data Array to the Destination Range.
drg.Value = Data
' Create a reference to the next Destination First Row Range.
Set drrg = drrg.Offset(dr)
End If
End If
Next sws
' The 'Clear Range' is the range spanning
' from the last 'Destination First Row Range'
' (which was referenced, but was not written to)
' to the bottom-most row range of the worksheet.
Dim crg As Range
Set crg = drrg.Resize(dws.Rows.Count - drrg.Row + 1)
crg.ClearContents
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the names of the worksheets of a workbook ('wb'),
' that are not included in a list ('ExceptionsList'),
' in an array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function ArrWorksheetNames( _
ByVal wb As Workbook, _
Optional ByVal ExceptionsList As String = "", _
Optional ByVal ListSeparator As String = ",", _
Optional ByVal FirstIndex As Long = 0) _
As Variant
If wb Is Nothing Then Exit Function
Dim wsCount As Long: wsCount = wb.Worksheets.Count
If wsCount = 0 Then Exit Function ' There could e.g. only be charts.
Dim IndexDiff As Long: IndexDiff = FirstIndex - 1
Dim LastIndex As Long: LastIndex = wsCount + IndexDiff
Dim Arr() As String: ReDim Arr(FirstIndex To LastIndex)
Dim n As Long: n = IndexDiff
Dim ws As Worksheet
If Len(ExceptionsList) = 0 Then
For Each ws In wb.Worksheets
n = n + 1
Arr(n) = ws.Name
Next ws
Else
Dim Exceptions() As String
Exceptions = Split(ExceptionsList, ListSeparator)
For Each ws In wb.Worksheets
If IsError(Application.Match(ws.Name, Exceptions, 0)) Then
n = n + 1
Arr(n) = ws.Name
End If
Next ws
End If
Select Case n
Case IndexDiff
Exit Function
Case Is < LastIndex
ReDim Preserve Arr(FirstIndex To n)
End Select
ArrWorksheetNames = Arr
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the range spanning from the first row
' of a given range ('rg') to the row containing the bottom-most
' non-empty cell of the given range's columns.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefColumns( _
ByVal rg As Range) _
As Range
If rg Is Nothing Then Exit Function
With rg.Rows(1)
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If lCell Is Nothing Then Exit Function ' empty range
Set RefColumns = .Resize(lCell.Row - .Row + 1)
End With
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the values of a range in a 2D one-based array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetRange( _
ByVal rg As Range) _
As Variant
If rg Is Nothing Then Exit Function
Dim rData As Variant
If rg.Rows.Count + rg.Columns.Count = 2 Then ' one cell only
ReDim rData(1 To 1, 1 To 1): rData(1, 1) = rg.Value
Else
rData = rg.Value
End If
GetRange = rData
End Function
' Irrelevant to the Question,
' but for a better understanding of `ArrWorksheetNames`.
Sub ArrWorksheetNamesTEST()
Const ExceptionsList As String = "Sheet1,Sheet2,Sheet3,Sheet4"
Const ListSeparator As String = ","
Const FirstIndex As Long = 4
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsNames As Variant
wsNames = ArrWorksheetNames(wb, ExceptionsList, ListSeparator, FirstIndex)
If IsEmpty(wsNames) Then
Debug.Print "No worksheets."
Else
Debug.Print "[" & LBound(wsNames) & "," & UBound(wsNames) & "]" _
& vbLf & Join(wsNames, vbLf)
End If
End Sub
You can use this to develop an array of values and then dump them into some collection sheet.
Sub grabAllSheets()
Const exclude_Sheet = "Result" ' name of sheet to drop data
Const tangoText = "On Stock"
Dim ws As Worksheet, aCell As Range
ReDim allvalues(1 To 6, 1 To 1)
Dim i As Long, c As Long
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> exclude_Sheet Then
For Each aCell In Intersect(ws.Range("E:E"), ws.UsedRange).Cells
If aCell.Value = tangoText Then
i = i + 1
ReDim Preserve allvalues(1 To 6, 1 To i)
For c = 1 To Range("F:F").Column
allvalues(c, i) = ws.Cells(aCell.Row, c).Value
Next c
End If
Next aCell
End If
Next ws
Dim theRow As Long
With Sheets(exclude_Sheet)
theRow = .Cells(.Rows.Count, 1).End(xlUp).Row
.Cells(IIf(theRow = 1, 1, theRow + 1), 1).Resize(i, 6).Value = _
Application.WorksheetFunction.Transpose(allvalues)
End With
End Sub

Excel VBA Repeatedly Delete Range with Specific String on Top Left

I would like to delete a certain range (3 rows & 19 columns) in excel that contains specific string (lns) on the top left of the range, repeatedly. They appear in different rows and columns, but the range size is always the same.
I have written a following code but nothing happens:
For Each vCell In ActiveSheet.UsedRange
If InStr(vCell.Value, "*lns*") Then
Range(Cells(vCell.Row, vCell.Column), Cells(vCell.Row + 2, vCell.Column + 18)).Delete shift:=xlShiftUp
End If
Next
It might be faster to locate the cells with Find
Option Explicit
Sub MyMacro()
Const ROW_SIZE = 3
Const COL_SIZE = 19
Const SEARCH = "lns"
Dim rng As Range, cel As Range
Dim n As Integer, s As Long
Set rng = ActiveSheet.UsedRange
Set cel = rng.Find(SEARCH, LookIn:=xlValues, lookat:=xlPart, _
searchdirection:=xlPrevious)
Do While Not cel Is Nothing
cel.Resize(ROW_SIZE, COL_SIZE).Delete shift:=xlShiftUp
n = n + 1
Set cel = rng.FindPrevious
If n > 1000 Then MsgBox "Code Error in Do Loop", vbCritical: Exit Sub
Loop
MsgBox n & " blocks deleted", vbInformation
End Sub
Delete Range 'Blocks'
Option Explicit
Sub DeleteBlocks()
Const rCount As Long = 3
Const cCount As Long = 19
Const Criteria As String = "lns"
Dim ws As Worksheet: Set ws = ActiveSheet
Dim rg As Range: Set rg = ActiveSheet.UsedRange
Dim fCell As Range
Set fCell = rg.Find(Criteria, rg.Cells(rg.Rows.Count, rg.Columns.Count), _
xlFormulas, xlPart, xlByRows)
Dim drg As Range ' Delete Range
Dim brg As Range ' Block Range
Dim fCount As Long ' Found Count
Dim FirstAddress As String
If Not fCell Is Nothing Then
FirstAddress = fCell.Address
Do
Set brg = Nothing
On Error Resume Next ' if in last 2 rows or 18 last columns
Set brg = Intersect(rg, fCell.Resize(rCount, cCount))
On Error GoTo 0
If Not brg Is Nothing Then
fCount = fCount + 1
Set drg = GetCombinedRange(drg, brg)
Set fCell = rg.FindNext(fCell)
End If
Loop Until fCell.Address = FirstAddress
If Not drg Is Nothing Then
drg.Delete Shift:=xlShiftUp
End If
If fCount = 1 Then
MsgBox "1 block deleted.", vbInformation, "DeleteBlocks"
Else
MsgBox fCount & " blocks deleted", vbInformation, "DeleteBlocks"
End If
Else
MsgBox "No blocks found.", vbExclamation, "DeleteBlocks"
End If
End Sub
Function GetCombinedRange( _
ByVal BuiltRange As Range, _
ByVal AddRange As Range) _
As Range
If BuiltRange Is Nothing Then
Set GetCombinedRange = AddRange
Else
Set GetCombinedRange = Union(BuiltRange, AddRange)
End If
End Function

Excel VBA search within range from previous column

I tried to implement this but I have a compiler error ("wrong qualification", or something like this, it's not an English version of Excel I have). I suppose it has to do with range / string things ?
Function SearchForTotal(givenLocation As Range, searchText As String) As Range
Debug.Print givenLocation 'gives $U$83
Dim startSearchFrom As String
'-1 because it's from previous column you'll be searching in
startSearchFrom = givenLocation.Offset(0, -1).Address
Debug.Print startSearchFrom
Dim i As Integer: i = startSearchFrom.Row
Do While i > 0
If (searchText = ThisWorkbook.Sheets("Sheet1").Range(startSearchFrom.column & i).Value) Then
Set SearchForTotal= Range(startSearchFrom.column & i)
Exit Do
End If
i = i - 1
Loop
End Function
The error comes from the line "Dim i As Integer: i = startSearchFrom.Row"
I also tried with the variable startSearchFrom as a range instead of a string (and then with the Set) but with this code I have a compiler error too ("types do not match").
startSearchFrom.column is a number so use .Cells(rowno,colno) rather than .Range()
Option Explicit
Function SearchForTotal(givenLocation As Range, searchText As String) As Range
Dim ws As Worksheet, iCol As Long, iRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
'-1 because it's from previous column you'll be searching in
iCol = givenLocation.Offset(0, -1).Column
iRow = givenLocation.Row
Do While iRow > 0
If (searchText = ws.Cells(iRow, iCol).Value) Then
Set SearchForTotal = ws.Cells(iRow, iCol)
Exit Do
End If
iRow = iRow - 1
Loop
End Function
Sub test()
Debug.Print SearchForTotal(Range("U83"), "test").Address
End Sub
Find Value Using Loop
Using the Find method would certainly be a better (more efficient) way.
Option Explicit
Function SearchForTotalLoop( _
ByVal GivenLocation As Range, _
ByVal SearchText As String) _
As Range
If GivenLocation Is Nothing Then Exit Function
' There's nothing to left of column `A`:
If GivenLocation.Column = 1 Then Exit Function
'-1 because it's from the previous column you'll be searching in
Dim rgStart As Range: Set rgStart = GivenLocation.Offset(0, -1)
Dim ws As Worksheet: Set ws = GivenLocation.Worksheet
Dim r As Long: r = rgStart.Row
Dim Col As Long: Col = rgStart.Column
Do While r > 0
If ws.Cells(r, Col).Value = SearchText Then ' A<>a
' To ignore case i.e. 'A = a', rather use the following:
'If StrComp(ws.Cells(r, Col).Value, SearchText, vbTextCompare) = 0 Then
Set SearchForTotal = ws.Cells(r, Col)
Exit Do
End If
r = r - 1
Loop
End Function
Sub SearchForTotalTEST()
' s - Start
' f - Found
Dim sCell As Range: Set sCell = Range("B83")
Dim fCell As Range: Set fCell = SearchForTotal(sCell, "Total")
If fCell Is Nothing Then Exit Sub
MsgBox "Starting Cell: " & sCell.Address & vbLf _
& "Found Cell: " & fCell.Address & vbLf _
& "Found Value: " & fCell.Value, vbInformation, "Find Total"
End Sub
EDIT
Using the Find method, you could do something like the following (not tested).
Function SearchForTotal( _
ByVal GivenLocation As Range, _
ByVal SearchText As String) _
As Range
' These two could be additionally used as arguments of the function.
Const FirstRow As Long = 1
Const ColOffset As Long = -1
If GivenLocation Is Nothing Then Exit Function
' There's nothing to left of column `A`:
If GivenLocation.Column + ColOffset < 1 Then Exit Function
If FirstRow > GivenLocation.Row Then Exit Function
Dim ws As Worksheet: Set ws = GivenLocation.Worksheet
If GivenLocation.Column + ColOffset > GivenLocation.Columns.Count _
Then Exit Function
If FirstRow > GivenLocation.Rows.Count Then Exit Function
Dim lCell As Range: Set lCell = GivenLocation.Cells(1).Offset(0, ColOffset)
Dim fCell As Range: Set fCell = ws.Cells(FirstRow, lCell.Column)
Dim rg As Range: Set rg = ws.Range(fCell, lCell)
Dim rCell As Range
Set rCell = rg.Find(SearchText, , xlFormulas, xlWhole, , xlPrevious)
If rCell Is Nothing Then Exit Function
Set SearchForTotal = rCell
End Function

Resources