VBA To Search Specific Column in Excel - vba

I am trying to search a specific column in Excel (Column K) using the below VBA code but when I run the macro it instead searches the whole sheet instead of the specified column.
The problem is it firstly finds 'mycell1' in an earlier column, i.e. in Column C instead of Column K which I don't want it to do.
I have also tried using 'xlByRows' in the 'Searchorder' which had the same issue.
Would greatly appreciate any help please
Thanks
Range("K:K").Select
Set foundcell1a = Selection.Cells.Find(What:=mycell1, After:=ActiveCell, LookIn:=xlValues, LookAt _
:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
Set foundcell1a = Cells.FindNext
If Not foundcell1a Is Nothing Then
foundcell1a.Activate
End If

Don't use .Select if you can possibly avoid it and most of the time, you can.
Try using With...End With constructs instead. Be as specific as you can with the object you want to operate on.
Sub SearchK()
Dim mycell1
Dim foundcell1a As Range
mycell1 = 1
With ActiveWorkbook.Worksheets("Sheet1").Range("K:K")
Set foundcell1a = .Find(mycell1, .Cells(.Rows.Count, 1))
Set foundcell1a = .FindNext(foundcell1a)
If Not foundcell1a Is Nothing Then
foundcell1a.Activate
End If
End With
End Sub
Without a With...End With, you would have to repeat all the object identifiers so:
Set foundcell1a = .Find(mycell1, .Cells(.Rows.Count, 1))
Would have to be expressed as:
Set foundcell1a = ActiveWorkbook.Worksheets("Sheet1").Range("K:K").Find(mycell1, .Cells(.Rows.Count, 1))
When VBA is evaluating a command it needs to evaluate each property preceding a period (.) every time it encounters it. Using ActiveWorkbook.Worksheets("Sheet1").Range("K:K") gets rid of 4 periods so it runs faster too.
The Set foundcell1a = .Find(mycell1, .Cells(.Rows.Count, 1)) is saying find mycell1 after the last used cell in column K so it loops back to find the first instance in column K regardless of the active cell.

Try this:
With Range("K:K")
Set LastCell = .Cells(.Cells.Count)
End With
Set FoundCell1a = Range("K:K").Find(mycell1, LastCell)
If Not FoundCell1a Is Nothing Then
FirstAddr = FoundCell1a.Address
Range(FirstAddr).Activate
End If
Hope this helps!

Related

Excel VBA - Search + Replace instead of For Each Loop?

I am looping through a column with ~5000 rows looking for a specific unique record. Once found, I offset and replace it with a value from a range. This is naturally rather resource intensive and I found it to occasionally freeze older machines running the macro.
My idea is now to replace this with a Search & Replace macro but am wondering if the performance is actually faster since the process of checking each cell in range for a value would still be the same?
Here the code I have so far. How would a Search & Replace look like and is worth it?
Sub Replace_List()
Dim rList As Range, cel As Range, n As Long
Dim fnd As Range
Dim fndFirst As String
Application.ScreenUpdating = False
With ThisWorkbook.Sheets("Settings")
Set rList = .Range("D4", .Range("D" & .Rows.Count).End(xlUp))
End With
For Each cel In rList
Set fnd = ThisWorkbook.Worksheets("Data").Columns("A:A").Find(What:=cel.Value, LookAt:=xlWhole)
If Not fnd Is Nothing Then
fndFirst = fnd.Address
Do
fnd.Offset(0, 1).Value = cel.Offset(0, 2).Value
Set fnd = ThisWorkbook.Worksheets("Data").Columns("A:A").FindNext(After:=fnd)
Loop While fnd.Address <> fndFirst
End If
Next
Application.ScreenUpdating = True
MsgBox "Replaced all items from the list.", vbInformation, "Replacements Complete"
End Sub
Note: This is not an answer, but rather something to ponder, and takes up way too much room for a comment.
This is pretty much the format I use on a "Search and Replace". I'm not sure if this ends up being any faster or not, but as you can see, it's not too different from your "find" statement. For me it works fine, but I'm not looking at thousands of records. Hope this helps you make a decision.
ThisWorkbook.Worksheets("Data").Columns("A:A").Replace What:=myValue1, Replacement:=myValue2, LookAt:=xlWhole, SearchOrder:=xlByColumns, MatchCase:=False, SearchFormat:=False, ReplaceFormat:=False

Summing values in loop VBA

I am attempting to sum a series of values based on unique identifiers I have isolated using dictionary keys, via the code below:
SearchVar = dictionary.Keys()(v)
Set FoundVar = CurrentPage.Find(What:=SearchVar, LookIn:=xlValues, _
LookAt:=xlPart, MatchCase:=False)
Set nextVar = CurrentPage.FindNext(FoundVar)
If Not FoundVar Is Nothing Then
Do Until FoundVar = nextVar
tempsum = tempsum + ws.Cells(FoundVar.Row, [ReferenceCell].Column).Value
Set nextVar = CurrentPage.FindNext(nextVar)
Loop
End If
However when I do so, the tempsum stay at 0. I'm certain that the cell reference in the tempsum addition portion is referencing the correct (non-zero) cells. What could be causing this issue?
Editing to add comment from below: The loop will indeed run only once. I modified it to run multiple times if there are multiple values by changing it to
Do until FoundVar.Address = NextVar.Address
but in these cases it doesn't sum the value for the last instance of FoundVar (as the FoundVar and NextVar addresses are the same). Any suggestions on how to have it include the last value as well? I'm thinking it can be done by saying 'Do until FoundVar.Address is Nothing" or so, but not sure on the correct syntax.
Your code has some mistake. Try this code.
Dim FoundVar As Range
Dim strAddress As String
SearchVar = dictionary.Keys()(v)
Set FoundVar = CurrentPage.Find(What:=SearchVar, LookIn:=xlValues, _
LookAt:=xlPart, MatchCase:=False)
'Set nextVar = CurrentPage.FindNext(FoundVar)
If Not FoundVar Is Nothing Then
strAddress = FoundVar.Address
Do
tempsum = tempsum + ws.Cells(FoundVar.Row, [ReferenceCell].Column).Value
Set FoundVar = CurrentPage.FindNext(FoundVar)
Loop Until strAddress = FoundVar.Address
End If

Excel VBA If Statement to Find Cells That Contain A String

I'm looking to create an IF/Else statment in VBA that when run will return a True or False value based on if a cell contains a certain string of text. So basically I want a True value returned if the cell contains the specified string or a False value if it does not contain the specified string. This formula needs to run down a range of cells not just one if that makes a difference. I'm thinking I need to use the InStr function, but I'm not 100% sure if that is correct or how to implement it. I am fairly new to VBA so any help I can get would be greatly appreciated as I have been stuck on this for several hours.
Thank You
Well this is a very badly asked question but I think everyone has needed some help at some point in life. That being said, here is the code you are asking for
Sub FindString()
'Declare the range
Dim rng As Range
'Assign the range to find
Set rng = ActiveSheet.Range("A1:A100")
'Loop though each cell
For Each cell In rng.Cells
'Check if cell has the string and set text
'of the next column to True or False
cell.Offset(0, 1).Value = IIf(InStr(1, cell, "stringToFind"), "True", "False")
Next
End Sub
Give it a try and let me know your comments
Why use VBA? An expression in cell can return True/False.
=ISNUMBER(FIND("something",A1))
I tested #3vts code and it runs but the output is wrong. This version works:
Sub FindString()
Dim rng As Range
Set rng = ActiveSheet.Range("A1:A100")
For Each cell In rng.Cells
If InStr(1, cell, "text to find") > 0 Then
cell.Offset(0, 1).Value = True
Else
cell.Offset(0, 1).Value = False
End If
Next
End Sub
I certainly hope you learned something in spite of the work was done for you.
May be the below one can help you, It gives you whether the excel contains the Word.
Dim ra As Range
Set ra = Cells.Find(What:=Word, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
If ra Is Nothing Then
'False (Not Found)
Else
'True (Found)
End If

Checking values in a column to change multiple row values

I have a spreadsheet with a good amount of data (more than 100,000 rows with columns a-h).
I know twenty or more distinct values in Column F are wrong and I know what they should be. For example, every occurrence of "pif" should be "pig" and "coe" should be "cow", etc.
(Note that there are multiple incorrect values (i.e. multiple "pif"s) for each.)
I'm currently building a macro to go through and fix these individually, and that part works:
Sub FixColumnF()
ActiveSheet.Columns("F").Replace What:= _
"pif", _
Replacement:="pig", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:= _
False, SearchFormat:=False, ReplaceFormat:=False
ActiveSheet.Columns("F").Replace What:= _
"coe", _
Replacement:="cow", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:= _
False, SearchFormat:=False, ReplaceFormat:=False
...
End Sub
My problem is that column A is used to keep track of errors, one of which is an incorrect value in column F. How do I erase the value in column A to indicate there is no longer an error for each row where the value in column F is fixed?
I'm extremely new to vba, so any help would be very much appreciated!
Siddharth posted his suggestions while I was testing/typing mine. My first suggestion is a simple variation of his first suggestion and offers no advantage that I can see. However, my second suggestion is different from either of his suggestions and may be appropriate.
You need to loop for each occurrence of "pif" and "coe" if you want to do something extra with each faulty value found. The code below shows how to replace every occurrence of "pif" by "pig" and then do something with column "A". If you like this technique, you would need to duplicate this code for "coe" and "cow".
Option Explicit
Sub ReplaceFaultyA()
Dim Rng As Range
' It is best to avoid "ActiveSheet" in case the use has called the
' macro with the wrong worksheet active. Probably this is not likely
' in this case but I like to follow good practice even if it not not
' necessary
With Worksheets("Data")
Do While True
' Are you sure all your Find parameters are correct? For example,
' "LookAt:=xlPart" means than "pif" in the middle of a word will
' be replaced by "pig". "LookAt:=xlWhole" may better match your
' requirement. I suggest you look up the specification of Find
' and consider the implications of each parameter.
Set Rng = .Columns("F").Find(What:="pif")
If Rng Is Nothing Then
' No [more] occurrences of "pif" in column F
Exit Do
Else
' Occurrences of "pif" found in column F
.Cells(Rng.Row, "F") = "pig"
' Amend column ""A" of Rng.Row as necessary
End If
Loop
End With
End Sub
Duplication my loop and replacing "pif" and "pig" by "coe" and "cow" in the duplicate is probably the simpliest solution if there are only two replacements. However, if there are many replacements, the technique below may be a better choice.
In this code, I place the faulty values and the matching good values in arrays. With this approach, one block of replacement code can handle an indefinite number of replacements providing the action for column A is the same for each replacement.
Sub ReplaceFaultyB()
Dim InxValue As Long
Dim Rng As Range
Dim ValueFaulty() As Variant
Dim ValueGood() As Variant
' The code below assumes there same number of entries in both arrays.
' You can add extra entries to the two arrays as necessary.
' This assumes the action for column "A" is the same for each faulty value
ValueFaulty = Array("pif", "coe", "appme")
ValueGood = Array("pig", "cow", "apple")
With Worksheets("Data")
For InxValue = LBound(ValueFaulty) To UBound(ValueFaulty)
Do While True
Set Rng = .Columns("F").Find(What:=ValueFaulty(InxValue))
If Rng Is Nothing Then
' No [more] occurrences of this faulty value in column F
Exit Do
Else
' Occurrences of faulty value found in column F
.Cells(Rng.Row, "F") = ValueGood(InxValue)
' Amend column ""A" of Rng.Row as necessary
End If
Loop
Next InxValue
End With
End Sub
There are two ways that I can think of.
Way 1
Use .Find/.FindNext to loop though all the cells which have say the word "pif". In that loop not only replace the word but also edit the value in Col A. For example (Untested)
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 Whoa
Set ws = Worksheets("Sheet1")
Set oRange = ws.Columns(5) '<~~ Column 5
SearchString = "pif"
NewString = "pig"
Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
'~~> Change value in Cell F
aCell.Value = Replace(aCell.Value, SearchString, NewString)
'~~> Change value in Cell A
aCell.Offset(, -5).Value = "Rectified"
Do
Set aCell = oRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
aCell.Value = Replace(aCell.Value, SearchString, NewString)
aCell.Offset(, -5).Value = "Rectified"
Else
Exit Do
End If
Loop
End If
Exit Sub
Whoa:
MsgBox Err.Description
End Sub
Way 2
Use Autofilter to filter Col F on the word "pif". Loop though all the cells in Col A and add the relevant message. Remove Autofilter and then run your original code (mentioned in your question) to do the replace in Col F. see THIS link on how to use Autofilter.

Find matching cell value in named range

I am trying to find the matching cell value in a named range in my excel workbook (.vba). I know the value that I am looking for, and also know the name of the range, and when I run the code the first time it runs with no problem, but on the second run with a new range name, I get an error.
I have tried a couple different ways to search the named range, and both ways result with the same error. The error is: "Method 'Range' of object '_Global' failed".
My initial code that I tried is:
'march through the list of racks
For i = iFirstRackRow To iLastRackRow
iCurrRackSize = Sheets("PLC I-O").Cells(i, 6).value
iHardwareIndexEnd = iHardwareIndex + iCurrRackSize - 1
rngCardsName = Trim(Sheets("PLC I-O").Cells(i, 2).value & "Cards")
'march through the rack hardware
For j = iHardwareIndex To iHardwareIndexEnd
modCardSize = 0
'march through each card in the rack
For Each zCell In Range(rngCardsName)
If zCell = Sheets("PLC I-O").Cells(j, 2) Then
modCardSize = Sheets("Links").Cells(zCell.Row, zCell.Column + 1).value
Exit For
End If
Next zCell
If modCardSize <> 0 Then
'io module matched
NumRows = NumRows + modCardSize
Else
'processor or adapter module found
NumRows = NumRows + 1
End If
Next
iHardwareIndex = iHardwareIndex + iCurrRackSize
Next
Or I have also tried:
Dim rngFoundCell As Range
With Range(rngCardsName)
Set rngFoundCell = .Find(What:=Sheets("PLC I-O").Cells(j, 2).value, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not rngFoundCell Is Nothing Then
'cell match was found
rngrow = rngFoundCell.Row
rngcol = rngFoundCell.Column
modCardSize = Sheets("Links").Cells(rngrow, rngcol + 1).value
Else
'cell match was not found
End If
End With
I am not sure what I am doing wrong here. Please help.
I think that the problem is the After:= parameter of your .Find . Try to change the parameter with the value After:=.Cells(1).
Thanks everyone! I found this issue. It was the Trim instruction. Since there were multiple spaces in the Sheets("PLC I-O").Cells(i,2).value, I needed to use a custom function to make sure all spaces were removed.