Excel VBA Find Function Side Effect? - excel

All. I am new to VBA and MS EXCEl 2010. I just started to play with the macro module in EXCEL yesterday, almost zero experience.
What I was trying to do is described as follows. First search for value records in a range in sheet1, then for each cell I found, I locate that row and pull out another cell value at that row. Using this value to do another search in a range in sheet2. I'll point out the problem I am having after my code. Here is the pesudcode.
Dim Found As Range
With RangeInSheet1
Set Found = .Find(value1)
If Not Found Is Nothing Then
firstAddress = Found.Address
Do
With RangeInSheet2
ColumnIndex = .Find(value2).Column
End With
Set Found = .FindNext(Found)
Loop While Not Found Is Nothing And Found.Address <> firstAddress
End If
End With
value1 is the key I used to search in RangeSheet1, and value2 in RangeSheet2. The above code goes through every record I found for value1 in sheet 1 and do another search in Sheet2.
Now let's Say value1 = 1, value2 =2007, and there are 5 records that contains value1 in sheet 1. The problem arises from this line of code "ColumnIndex = .Find(value2).Column".
Supposedly, for all the five found records, value of Found should always be 1 after "Set Found = .FindNext(Found)" is executed . But, after I added this ColumnIndex code, value of Found is set to 2007, which is so weird to me. Anyone knows what the problem is? Any help will be appreciate. I really need to keep the Found behaves "normal" as I want.
If anything is unclear, please let me know

.Find/.Findnext remembers the last setting. And hence it is always advisable to completely Specify the parameters. specially After:= parameter. It will also remember what was your last search term i.e What:=
Here is a demonstration on how to work with .Find/.Findnext
Also do not use Value2 as a variable. It is a reserved word. Instead of using Value1 and Value2, I am using sSearch1 and sSearch2 in the below code
Let's say your sheets look like this
Now Try this code
Sub Sample()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rngWs1 As Range, rngWs2 As Range
Dim aCell As Range, bCell As Range, cCell As Range, dCell As Range, eCell As Range, cl As Range
Dim sSearch1, sSearch2
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set rngWs1 = ws1.Range("A1:A10")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
Set rngWs2 = ws2.Cells
With ws1
For i = 1 To 10
sSearch1 = .Range("A" & i).Value
Set aCell = .Range("A" & i)
If Len(Trim(sSearch1)) <> 0 Then
Set aCell = rngWs1.Find(What:=sSearch1, After:=aCell, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
sSearch2 = aCell.Offset(, 1).Value
With ws2
Set bCell = rngWs2.Find(What:=sSearch2, After:=.Range("A1"), LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not bCell Is Nothing Then
Debug.Print "For " & sSearch1 & ", " & sSearch2 & " Found in " & bCell.Address
Set cCell = bCell
Do
Set bCell = rngWs2.FindNext(After:=bCell)
If Not bCell Is Nothing Then
If bCell.Address = cCell.Address Then Exit Do
Debug.Print "For " & sSearch1 & ", " & sSearch2 & " Found in " & bCell.Address
Else
Exit Do
End If
Loop
End If
End With
End If
End If
Next
End With
End Sub
This is the result that we get.

Related

Setting a range to nothing, but then being able to use the range later in the code

I've got the below to copy data based on two variables to the appropriate row in another sheet. It works (HOORAY!). However what I'm struggling to get my head around is the if logic I have used. I understand as it saying "If we find both cells, we redefine the Found to be nothing in order to end the loop". However as I now have set Found to Nothing, how is the code then able to find the address previously stored in Found and paste the data to it?
Sub copy_transpose()
Dim rng_source As Range
Dim Found As Range, Firstfound As String
Dim rngSearch As Range
Dim Criteria As Variant
Set rng_source = ThisWorkbook.Sheets("KPI").Range("H6:H100")
Set rngSearch = Sheets("Table").Range("A:A")
Criteria = Sheets("KPI").Range("C2:D2").Value
Set Found = rngSearch.Find(What:=Criteria(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Found Is Nothing Then
Firstfound = Found.Address
Do
If Found.EntireRow.Range("B2").Value = Criteria(1, 2) Then Exit Do 'Match found
Set Found = rngSearch.FindNext(After:=Found)
If Found.Address = Firstfound Then Set Found = Nothing
Loop Until Found Is Nothing
End If
If Not Found Is Nothing Then
Application.Goto Found
rng_source.Copy
Sheets("Table").Range(found.Offset(0, 1), found.Offset(0, 7)).PasteSpecial Transpose:=True
Else
MsgBox ("Error")
End If
End Sub

Use VBA in Excel to Find and Update Related Records on a Different Sheet from Working Sheet

I have two spreadsheets. Each spreadsheet contains rows with various bits of information on them, including a unique identifier number (an ISBN in this case).
I am trying to make a script that determines a record is present on the working sheet (obtaining ISBN from column A – working sheet is called ePubWorking), and marks a column (V) on the master sheet (ePubMaster) in the row that contains the same ISBN as found on the previous sheet (the ISBN on the new sheet is also kept in column A). It needs to do this for each record found on the ePubWorking sheet.
I’ve tried a few variants of code I’ve found on here, but I can’t seem to get anything to work. This is what I’m currently working with (which doesn’t appear to be doing anything):
Dim rCell As Range
Dim rFind As Range
Dim iColumn As Integer
For Each rCell In Sheets("ePubWorking").Range("A2", Sheets("ePubWorking").Cells(Rows.Count, "A").End(xlUp))
Set rFind = Sheets("ePubMaster").Rows(1).Find(What:=Trim(rCell.Value), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
rCell.Offset(0, 2).Value = "Sent"
If Not rFind Is Nothing Then
rFind.Offset(0, 21).Value = "Sent"
End If
Next rCell
Nothing is happening using the above (or any of my other variants). I can't even get the "Sent" part to appear on the secondary sheet.
Can anyone point me in the right direction please?
Ok so thanks for the guidance, obviously I'd been banging my head on frankenstein attempts for too long and got blinded to what I was doing. As Zac pointed I was looking along the wrong axis on the ePubMaster sheet.
Working code:
Dim wb As Workbook: Set wb = ThisWorkbook
Dim workingSheet As Worksheet: Set workingSheet = wb.Sheets("ePubWorking")
Dim masterSheet As Worksheet: Set masterSheet = wb.Sheets("ePubMaster")
Dim workingRange As Range: Set workingRange = Range(workingSheet.Range("A2"), workingSheet.Cells(workingSheet.Rows.Count, "A").End(xlUp))
Dim rCell As Range
Dim rFind As Range
For Each rCell In workingRange
If Not rCell.Value = vbNullString Then
Set rFind = masterSheet.Rows.Find(What:=Trim(rCell.Value), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
rCell.Offset(0, 2).Value = "Sent"
If Not rFind Is Nothing Then
rFind.Offset(0, 21).Value = "Sent"
End If
End If
Next rCell

How to specify what worksheet to use with find/with

I want to search a range A1-A99 in a certain sheet (wsCaseinfo) for the word Overview. I get a 1004 error on the 'with' line.
The code is part of a larger code using 3 different sheets in 2 different files. Code cycles through 100 files, so something efficient would be appreciated. Many thanks for your help.
With wsCaseinfo.Range(Cells(1, 1), Cells(99, 1))
Set cellx = .Find(what:="Overview", LookAt:=xlPart)
End With
You need to append the Cells() with the parent sheet:
With wsCaseinfo.Range(wsCaseinfo.Cells(1, 1), wsCaseinfo.Cells(99, 1))
Other wise the Cells() will refer to the active sheet and not the same sheet as the Range().
You can also nest a With in the first With
With wsCaseinfo
With .Range(.Cells(1, 1), .Cells(99, 1))
Set cellx = .Find(what:="Overview", LookAt:=xlPart)
End With
End With
With Sheets("wsCaseinfo").Range(Sheets("wsCaseinfo").Cells(1, 1), Sheets("wsCaseinfo").Cells(99, 1))
Set cellx = .Find(What:="Overview", LookAt:=xlPart)
End With
Three Four ways of referring to a sheet:
The name (as above)
The index (eg. Sheets(4))
The codename (eg. Sheet4)
Using a variable eg.
Dim MySheet As Worksheet
Set MySheet = ThisWorkbook.Worksheets("Sheet4")
then using
MySheet.Cells()
If you use Cells(), you must qualify. Instead:
Sub luxation()
Dim cellx As Range, wsCaseinfo As Worksheet
Set wsCaseinfo = Sheets("Sheet1")
With wsCaseinfo.Range("A1:A99")
Set cellx = .Find(what:="Overview", LookAt:=xlPart)
MsgBox cellx.Address
End With
End Sub
Change the Set statement to suit your needs.
Find in Worksheet
Shortest
With wsCaseInfo
Set cellx = .Range("A1:A99").Find("Overview", , xlValues, xlPart)
End With
Short
With wsCaseInfo
Set cellx = .Range("A1:A99").Find("Overview", , xlValues, xlPart)
If Not cellx Is Nothing Then
Debug.Print cellx.Address
Else
Debug.Print "Cell range not found."
End If
End With
Long
Sub FindInWorksheet()
Const cSheet As String = "Sheet1"
Dim wsCaseInfo As Worksheet
Dim cellx As Range
Set wsCaseInfo = ActiveWorkbook.Worksheets(cSheet)
With wsCaseInfo
' Full
'Set cellx = .Range("A1:A99").Find("Overview", .Range("A99"), _
xlValues, xlPart, xlByColumns, xlNext, False)
' Preferable
'Set cellx = .Range("A1:A99").Find("Overview", , _
xlValues, xlPart, xlByColumns)
' Minimal
Set cellx = .Range("A1:A99").Find("Overview", , xlValues, xlPart)
If Not cellx Is Nothing Then
Debug.Print cellx.Address
Else
Debug.Print "Cell range not found."
End If
End With
End Sub
Find Method Reminder
The 1st argument, What, contains the data to search for and is required. All other arguments are optional.
By omitting the second argument, After, your search starts from
A2 and ends with A1 which is often preferable because we have
headers in the first row. But to start the search from A1 and end
with A99, you would have to set the After parameter to "A99".
The 3rd, 4th and 5th arguments, LookIn, LookAt and
SearchOrder, are SAVED each time a Find is 'performed'.
By setting the LookIn argument's parameter to xlValues you prevent possible
searching in formulas (or comments).
LookAt is correctly set to xlPart to find values of the What parameter (Overview) in cells where it is only a part of them e.g. Product Overview or Overview of Parts will be found. Or is it?
SearchOrder can safely be omitted, since we're searching in a one-column range.
The 6th argument, SearchDirection, is by default xlNext which
is used in the code and can therefore be safely omitted.
The 7th argument, MatchCase, is by default False to find OverView or ovErView which is probably no issue here.
You could try:
EDITED VERSION
Option Explicit
Sub test()
Dim rngToSearch As Range
Dim Result As Range
Set rngToSearch = wsCaseinfo.Range("A1:A99")
Set Result = rngToSearch.Find(What:="Overview", LookIn:=xlValues, LookAt:=xlWhole)
If Not Result Is Nothing Then
MsgBox "The word ""Overview"" appears in:" _
& vbNewLine & "Row " & Result.Row _
& vbNewLine & "Column " & Result.Column _
& vbNewLine & "Address " & Result.Address
Else
MsgBox "The word ""Overview"" does not exist in range " & rngToSearch.Address & "."
End If
End Sub

VBA - Type Mismatch Error for copying cells linked to a certain keyword in a column

I am trying to automate bank statement reconciliation. I need to find a certain word in column B, then copy the value 4 columns to right of that word, as well as the value found 3 rows down and one column to the left. My goal is to find these two values every times that keyword is found and copy them to a second sheet. I'm experiencing a type mismatch error that I can't seem to figure out.
First off, I'm as new as can be to macros. I've adapted my code from this post: VBA - find specific word in column and copy the below's cell on different sheet. The main adaption seems to be finding two separate values rather than two whole lines, which seem to require some extra lines of code incorporating a second range. The error occurs when I try and set the second range, on this line:
Set rngCopy2 = .Rows(.Cells(aCell.Row) + 3) & (.Cells(aCell.Column) - 1)
I tried changing .Rows to .Columns where it's aCell.Column but that didn't seem to work. I'm positively stumped, and would appreciate any help someone could provide.
Note that I made some small edits to the syntax of the code and added .Cells before the aCell when setting ranges.
Also, as a separate and quick question, if I have a name in a cell that could be anywhere from 5 to 18 characters long but that is followed by a constant such as "ABC Staff", is there a way to take everything in that cell up until it says "ABC Staff"?
Dim ws As Worksheet
Dim rngCopy As Range, aCell As Range, bCell As Range
Dim rngCopy2 As Range
Dim strSearch As String
strSearch = "Salary Transfer"
Set ws = Worksheets("Summary")
With ws
Set aCell = .Columns(2).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
If rngCopy Is Nothing Then
Set rngCopy = .Rows(.Cells(aCell.Column + 4))
Set rngCopy2 = .Rows(.Cells(aCell.Row) + 3) & (.Cells(aCell.Column) - 1)
Else
Set rngCopy = Union(rngCopy, .Rows(.Cells(aCell.Column + 4)))
Set rngCopy2 = Union(rngCopy2, .Rows(.Cells(aCell.Row + 3) & .Cells(aCell.Column - 1)))
End If
Do
Set aCell = .Columns(2).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
If rngCopy Is Nothing Then
Set rngCopy = .Rows(.Cells(aCell.Column + 4))
Set rngCopy2 = .Rows(.Cells(aCell.Row) + 3) & (.Cells(aCell.Column) - 1)
Else
Set rngCopy = Union(rngCopy, .Rows(.Cells(aCell.Column + 4)))
Set rngCopy2 = Union(rngCopy2, .Rows(.Cells(aCell.Row + 3) & .Cells(aCell.Column - 1)))
End If
Else
Exit Do
End If
Loop
Else
MsgBox SearchString & " not Found"
End If
If Not rngCopy Is Nothing Then rngCopy.Copy Sheets("Output").Rows(1)
If Not rngCopy2 Is Nothing Then rngCopy2.Copy Sheets("Output").Rows(2)
End With

.FindNext failing after a .Find function (excel vba)

I am trying to use .Find and .FindNext to search through a single column of data. I first need to find the first cell containing the value "Total". The cell I'm trying to get to is the third cell AFTER the "Total" cell to contain the value "Tech". It is known for certain that the Cells(1, 1) does not contain "Tech" or "Total".
Dim FirstTotal As Range
Dim SearchRng As Range
Dim ResultRng As Range
Set SearchRng = Range("A:A")
Set FirstTotal = SearchRng.Find(What:="Total", After:=Cells(1, 1), SearchDirection:=xlNext)
Set ResultRng = SearchRng.Find(What:="Tech", After:=FirstTotal, SearchDirection:=xlNext)
SearchRng.FindNext().Activate
SearchRng.FindNext().Activate
About 50% of the times I've run this code, I've been stopped by a type mismatch error on the line beginning with Set ResultRng =. The rest of the time, the code has run all the way through, but the results look as though the final two lines of code were ignored completely.
I suspect that the answer here is pretty elementary, but I'm pretty new to excel vba and no resources I've found so far have answered this. Please help!
Would this help?
Sub Sample()
Dim oRange As Range, aCell As Range, bCell As Range
Dim ws As Worksheet
Dim SearchString As String, FoundAt As String
On Error GoTo Err
Set ws = Worksheets("Sheet3")
Set oRange = ws.Columns(1)
SearchString = "2"
Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
FoundAt = aCell.Address
Do
Set aCell = oRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
FoundAt = FoundAt & ", " & aCell.Address
Else
Exit Do
End If
Loop
Else
MsgBox SearchString & " not Found"
End If
MsgBox "The Search String has been found at these locations: " & FoundAt
Exit Sub
Err:
MsgBox Err.Description
End Sub
If "Total" isn't found, then FirstTotal will be Nothing, which will result in a Type Mismatch when you try to use FirstTotal for the "After" argument in the ResultRange Find (the 2nd line). This will prevent that error:
Set FirstTotal = SearchRng.Find(What:="Total", After:=Cells(1, 1), SearchDirection:=xlNext)
If Not FirstTotal is Nothing Then
Set ResultRng = SearchRng.Find(What:="Tech", After:=FirstTotal, SearchDirection:=xlNext)
End If
Generally speaking any dependent Finds need to be treated this way.
Clearly, some kind of Else statement is required here, but I don't know what that would be.
I have observed the FindNext method fail to find the next occurrence of the searched item when applied in a function with parameters, which is invoked from a cell. The Find method (to search the first occurrence) does work as expected.

Resources