I searched for the answer to this question, and came VERY CLOSE with
VBA: need decide if result of FIND method is NOTHING or "" (empty)
but I couldn't quite understand how to fix my problem. It is pretty much the same, I am using find to look up something in another workbook, and if the find() can't find what I'm looking for, it throws an error. I tried the suggestions in the link above, but I agree with https://stackoverflow.com/users/478884/tim-williams that since my object is still empty, that the IIF() will error still.
Do Until Row > LastRow
On Error GoTo MFGPNError
PLRow = Workbooks(WB2).Sheets("5727").Range("C:C").Find(what:=Workbooks(WB1).Main.Cells(Row, 2).Value2, lookat:=xlWhole, searchorder:=xlByRows, MatchCase:=True).row
VREFLookup:
On Error GoTo VREFError
PLRow = Workbooks(WB2).Sheets("5727").Range("D:D").Find(what:=Workbooks(WB1).Main.Cells(Row, 2).Value2, lookat:=xlWhole, searchorder:=xlByRows, MatchCase:=True).row
Then my error trapping:
Exit Sub
MFGPNError:
If PLRow Is Empty Then
Workbooks(WB1).Main.Cells(Row, 3) = ""
'If IIf(PLRow Is Empty, "", PLRow) = "" Then
'setting MPN to be "" and moving to VREF lookup
On Error GoTo -1
GoTo VREFLookup
End If
'-----
Exit Sub
VREFError:
If IIf(PLRow Is Nothing, "", PLRow) = "" Then
'setting MPN to be "" and then adding cleaned up pn to array?
WB1.Main.Cells(Row, 3) = ""
On Error GoTo -1
GoTo CleanPN
End If
On my first Error Trap, I commented out the IIF() because it threw an error, and tried a regular IF(), still an error..
My question is, how can I keep going through my macro, if my Find() throws an error? I would like to just skip that particular Find(), and move on to the next row.
Also, is my error-handling any good? I've never really had to do much of it (mainly do to my macros being very simple)
I think this is your problem: the result of the .Find method is a range object, which can be Nothing. You are trying to evaluate Nothing.Row which raises an error.
Rather than deal with messy error handlers and confusing GoTo statements, it's best to simply trap that error and deal with it properly.
First, declare a range object and use that to return the result of the .Find.
Dim rngFound as Range
'## Attempt the lookup in Column C:
Set rngFound = Workbooks(WB2).Sheets("5727").Range("C:C").Find( _
what:=Workbooks(WB1).Main.Cells(Row, 2).Value2, _
lookat:=xlWhole, searchorder:=xlByRows, MatchCase:=True)
Then, you can deal with this rngFound variable, and test whether it's Nothing. If it is, then do another Find against column D:
'## If not found, look for it in column D:
If rngFound Is Nothing Then
Set rngFound = Workbooks(WB2).Sheets("5727").Range("D:D").Find( _
what:=Workbooks(WB1).Main.Cells(Row, 2).Value2, _
lookat:=xlWhole, searchorder:=xlByRows, MatchCase:=True)
End If
If the second find also fails, then you do something else which you already know how to do:
If rngFound Is Nothing Then
'## DO SOMETHING ELSE ##
End If
Then, you can assign to your PLRow variable
If rngFound Is Nothing then
PLRow = Empty '## Or modify as needed.
Else:
PLRow = rngFound.Row
End If
As a best practice, you should avoid using On Error GoTo... statements whenever possible, especially when the error can be suitably trapped without an error handler. Also, within your error handlers (if you absolutely must use them for some other reason), you should probably do Err.Clear and also Resume Next instead of GoTo VREFLookup.
Related
I do some filtering on a range and copy that filtered range with
myRange.SpecialCells(xlCellTypeVisible).Copy
As soon as the filter filters all cases I get
Error 1004 No cells were found
I am looking for a way to check (without an On Error) if the filtered range is empty.
I already tried to set a range with lastRow = .Cells(.Rows.Count, ColumnName).End(xlUp).Row and check if lastRow > 0 but with this way I also count the filtered (or hidden) row contents.
I also tried
Sub test()
Dim rngStart As Range
Dim rngFiltered As Range
Set rngStart = Sheets(1).Range("A1:A6")
Set rngFiltered = rngStart.SpecialCells(xlCellTypeVisible).Select
If rngFiltered.Rows.Count = 0 Then
MsgBox ("No Cases")
Else
MsgBox ("Found Cases")
End If
End Sub
But here I get the error "No cells found" in the Set rngFiltered line as well.
I have no header row, since the filter is so complex that I programmed it without using the .Sort function
Dim rngStart As Range
Dim rngFiltered As Range
'...
'...
Set rngFiltered = Nothing '<<< reset rngFiltered if running this code in a loop...
On Error Resume Next
Set rngFiltered = rngStart.SpecialCells(xlCellTypeVisible)
On Error Goto 0
If not rngFiltered is Nothing then
rngFiltered.Copy
End If
'...
'...
I stored the solution into a function. Here I use an error on mechamism.
Function errorCatchEmptyFilter(ByRef rngstart As Range) As Boolean
errorCatchEmptyFilter = False
'here I get an error if there are no cells
On Error GoTo hell
Set rngFiltered = rngstart.SpecialCells(xlCellTypeVisible)
Exit function
hell:
errorCatchEmptyFilter = True
End Function
What I do is I am counting filtered rows :
Sheets("Sheet1").Range("A2:Z2").AutoFilter
Sheets("Sheet1").Range("A2:Z2").AutoFilter Field:=1, Criteria1:=filter1
If Sheets("Sheet1").AutoFilter.Range.Columns(4).SpecialCells(xlCellTypeVisible).Count > 1 Then
you can change number of column to suits your needs
Got the same problem, but for filtering named table, solved it this way*:
instead of applying several filters, I've added a column at the end of the table, with a formula that would return true for the rows I wanted to have filtered in, false for filtered out.
Then, I've applied one filter for that true value and added a cell that would count all true values in that column
in vba, firstly reapply filter for the table then if that counter is greater than 0 do .SpecialCells(xlCellTypeVisible).Copy, else skip to next step (i was doing that in a loop)
*I know that this question is from 2015, but I've ended here in 2019 googling similar problem so I'm leaving my solution.
BACKGROUND: I got a cool Array Formula and it works perfect in Excel. Now I'm trying to do the same formula, but with VBA. So I typed the Array Formula in a cell and recorded with a macro. The formula works perfect. The macro recorder gets me this:
Selection.FormulaArray = _
"=INDEX('[HOGARES ALBACETE.xlsx]21076'!C1,MATCH(MAX(IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""["" &R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2)),IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""[""&R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2),0),1)"
If I try to run the code above, I get error 1004. The sub has just that line. Nothing else.
After some researching I got into this:
VBA Run time error 1004: Unable to set the formulaarray property of the range class
Entering Long Array Formulas In VBA
So I splitted the formula into 2 parts:
Dim theFormulaPart1 As String
Dim theFormulaPart2 As String
Dim MiReemplazo As String
MiReemplazo = "cacota"
theFormulaPart1 = "=INDEX('[HOGARES ALBACETE.xlsx]21076'!C1,MATCH(MAX(IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""["" &R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2))," & MiReemplazo & ",0),1)"
theFormulaPart2 = "IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""[""&R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2)"
With ActiveSheet.Range(“F2”)
.FormulaArray = theFormulaPart1
.Replace MiReemplazo, theFormulaPart2
End With
And I get no errors, but the part .Replace MiReemplazo, theFormulaPart2 does nothing (I mean, the replace does not happen, but the code executes)
Also, tried with:
ActiveSheet.Range("F2").FormulaArray = theFormulaPart1
DoEvents
Cells.Replace What:=MiReemplazo, Replacement:=theFormulaPart2, LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
But nothing. So I'm kinda out of ideas.
Also, checked the lenght of both formulas strings (173,107). Do I need sorther strings?
THINGS I'M PRETTY SURE ARE NOT A PROBLEM:
The formula in Excel works if I type it manually. So is not a problem of the Formula itself
I'm just working in 1 cell and trying to get 1 value in the cell of other workbook, so is not a problem of memory or resources.
Thanks in advance.
I'd bet your Excel is not set to use R1C1 referencing, so the replace won't work as you're trying to put an R1C1 referenced string into an A1 style formula. Try using:
Application.ReferenceStyle = xlR1C1
With ActiveSheet.Range("F2")
.FormulaArray = theFormulaPart1
.Replace MiReemplazo, theFormulaPart2
End With
Application.ReferenceStyle = xlA1
This is a little time consuming due to forced recalculation of a moved object but it seems to work well.
Problem: external workbook references are pushing array formula over the character limit.
Solution: a) move the external worksheet to the local workbook b) complete the array formula insertion c) move the local worksheet back to the external workbook and let Excel figure it out.
Sub arrayFormulaTooBig()
Dim ha2ndx As Long, wbha As Workbook, wbf As Workbook
Dim sel As Range
Set sel = Selection
Set wbha = Workbooks("HOGARES ALBACETE.xlsx")
Set wbf = sel.parent.parent
'Application.Calculation = xlCalculationmanual
'Application.ScreenUpdating = False
'move the external worksheet to local and reduce worksheet name to minimum characters
With wbha
If .Worksheets.Count = 1 Then
.Worksheets.Add after:=.Worksheets(.Worksheets.Count)
.Worksheets(.Worksheets.Count).Name = "to be removed"
End If
With .Worksheets("21076")
ha2ndx = .Index
.Move after:=wbf.Worksheets(wbf.Worksheets.Count)
End With
End With
'minimize worksheet name
wbf.Worksheets("21076").Name = ChrW(215)
'from 282 characters
'Selection.FormulaArray = _
"=INDEX('[HOGARES ALBACETE.xlsx]21076'!C1,MATCH(MAX(IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""["" &R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2)),IF(RIGHT('[HOGARES ALBACETE.xlsx]21076'!C1,LEN(R[-1]C)+2)=""[""&R[-1]C&""]"",'[HOGARES ALBACETE.xlsx]21076'!C2),0),1)"
'to 137 characters
sel.FormulaArray = _
"=INDEX(×!C1,MATCH(MAX(IF(RIGHT(×!C1,LEN(R[-1]C)+2)=""["" &R[-1]C&""]"",×!C2)),IF(RIGHT(×!C1,LEN(R[-1]C)+2)=""[""&R[-1]C&""]"",×!C2),0),1)"
With wbf
With .Worksheets(ChrW(215))
.Move before:=wbha.Worksheets(ha2ndx)
End With
End With
'restore worksheet name
wbha.Worksheets(ChrW(215)).Name = "21076"
On Error Resume Next
Application.DisplayAlerts = False
wbha.Worksheets("to be removed").Delete
Application.DisplayAlerts = True
On Error GoTo 0
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
currently I am trying to scan my book for an if statement I wrote, where it identifies unique ID's then returns "Not in Book" if that id no longer exists.
To clean the book of all the area's where I see "Not in Book" I created a small bit of code to purge all of those entries.
Dim MWS As Worksheet
Set MWS = Sheets("Marks")
MWS.Cells.Find(what:="Not in Book", LookIn:=xlValues).EntireRow.Delete
What is the appropriate way for this statement to...
A. Scan the entire book for this phrase and delete that row as opposed to deleting one row at a time.
B. To error control this statement so when "Not in Book" does not exist the user will not get an error, rather nothing will happen or a msgbox will appear stating the book is clean.
Thanks,
You can do it like this. Assign the search to a range variable and check if it's Nothing.
Sub x()
Dim rFind As Range, MWS As Worksheet
Set MWS = Sheets("Marks")
With MWS
Set rFind = .Cells.Find(what:="Not in Book", LookIn:=xlValues, _
Lookat:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not rFind Is Nothing Then
Do
rFind.EntireRow.Delete
Set rFind = .Cells.Find("Not in Book")
Loop Until rFind Is Nothing
Else
msgbox "Term not found"
End If
End With
End Sub
I think the simplest way is a loop through your cells and check if the cell value equals your word then delete the row. Here is the code.
Sub CleanTheSheet()
dim rng as range
for each rng in activesheet.usedrange.cells ' Here you can specify name of your sheet or the range if you have such a info
if rng.value ="Not in Book" then rng.entirerow.delete
next
if worksheetfunction.countif(activesheet.usedrange,"Not in Book") = 0 then msgbox "The Sheet is Clean Now!"
END SUB
I'm trying to write a subroutine that searches through a range of cells, and returns the column number of the first cell with the specified value. This is what I have so far:
Dim StartCol As Long
Dim rngSearch As Range
Dim rngFound As Range
USedCol = ActiveWorkbook.Sheets("...").UsedRange.Columns.Count
Set rngSearch = Range(Cells(6, 2), Cells(6, USedCol))
Set rngFound = rngSearch.Find(What:="Jun", LookIn:=xlValues, LookAt:=xlWhole)
StartCol = rngFound.Column
Unfortunately this gives me the error "object variable or with block variable not set". The error must be coming from a block variable not being set since I'm not using any with statements. I've used almost this exact same line of code in other programs and it has worked perfectly. I'm not sure what I'm missing here. I greatly appreciate any help, thanks.
Also, when I debug, the line that gets highlighted is
StartCol = rngFound.Column
Let me know if you need any other information.
This would happen if the search was unsuccessful, from MSDN:
Range.Find Method (Excel)
...
This method returns Nothing if no match is found.
Link: https://msdn.microsoft.com/en-us/library/office/ff839746.aspx
You can test for this:
If rngFound Is Nothing Then
'Code to handle not found case
Else
StartCol = rngFound.Column
End If
I have to following code snippet ...
Public Sub FindText(path As String, file As String)
Dim Found As Range
myText = "test("
MacroBook = ActiveWorkbook.Name
' Open the File
Workbooks.Open path & file, ReadOnly:=True, UpdateLinks:=False
For Each ws In Workbooks(file).Worksheets
With ws
Set Found = .UsedRange.Find(What:=myText, LookIn:=xlFormulas, _
LookAt:=xlPart, MatchCase:=False)
If Not Found Is Nothing Then
' do stuff
' ...
I see in the debugger that Found contains Error 2015! The sheet contains the text I want in the formula.
Any ideas why I'm getting the error?
Thanks
As follow up from comments to the Q, Error 2015 occurs because your formula in the sheet returns #VALUE! error. You can handle it using IsError:
If Not Found Is Nothing Then
If Not IsError(Found) Then
' do sth
End If
End If
You don't need to use 'Set' in your code. You only use this to assign a reference to an object. Try:-
For Each ws In Workbooks(file).Worksheets
With ws
Found = .UsedRange.Find(What:=myText, LookIn:=xlFormulas, _
LookAt:=xlPart, MatchCase:=False)
If Not Found Is Nothing Then
' do stuff
' ...
Hopefully this should work.