I would like to select the first non-blank row above the selected cell (minus offset). For example, if a find Machine 1 in the sheet Grupos Produção I want to return the ******* Grupo 1 ******* string.
********** Grupo 1 **********
Machine 1
Machine 2
I have the following so far, but it's not returning what I need.
Dim FindString As String
Dim Rng As Range
FindString = Lcell.Value
If Trim(FindString) <> "" Then
With Sheets("Grupos Produção").Range("A:Z")
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Application.Goto Rng, True
upperRow = .Cells(Rng.Row, Rng.Column - 1).End(xlDown).Row
Else
MsgBox "Nothing found"
End If
End With
End If
I'm not sure I understand your code, but I think you are looking for something like this:
...
...
If Not Rng Is Nothing Then
Do While Rng.Row > 1 And Rng.Offset(-1, 0).Value <> ""
Set Rng = Rng.Offset(-1, 0)
Loop
...
Once the cell is found, it works its way up until it finds an empty cell and stops just before.
This will find the first non-blank cell (which will indicate the row is not blank) above the selected cell.
You need to check for:
If the rest of the sheet is empty it will return the same address as your selection.
If all cells above the selection are empty it will start from the bottom of the sheet until it reaches your selection again.
As you said the first non-blank cell it's using the * wildcard to search, and to make it look up from the selection it uses xlPrevious.
Still need to check if rng is nothing in case the entire sheet is empty.
Sub Test()
Dim Rng As Range
With ThisWorkbook.Worksheets("Sheet1").Range("A:Z")
Set Rng = .Cells.Find(What:="*", _
After:=Selection, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious)
If Not Rng Is Nothing Then
If Rng.Address = Selection.Address Or Rng.Row > Selection.Row Then
MsgBox "Nothing found"
Else
Rng.Select
End If
End If
End With
End Sub
I managed to get what I need based on #Sam 's answer
If Not Rng Is Nothing Then
Do While Rng.Row > 1 And Rng.Offset(-1, 0).Value <> ""
Set Rng = Rng.Offset(-1, 0)
Loop
grupo = Rng.Offset(-1, -1).Value
Lcell.Value = grupo
End If
Related
I have this sheet where I want to use Find and FindNext to search for values on another sheet BD and copy them to my main sheet Plan1 if the value on alocacao matches cells on Column 5.
I used to have 4 spaces with named ranges tecnico1, tecnico2, tecnico3 and tecnico4 to paste the values and the code works fine.
This is how it looks:
And the BD sheet:
And this is the code:
Sub VerifProd_Click()
Dim FoundCell As Range, FirstAddr As String, fnd As String, i As Long
fnd = Sheets(1).Range("alocacao").Value
Set FoundCell = Sheets("BD").Columns(5).Find(what:=fnd, _
After:=Sheets("BD").Cells(Rows.Count, 5), Lookat:=xlPart, _
LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If FoundCell Is Nothing Then Exit Sub
Do
i = i + 1
Sheets("Plan1").Range("tecnico" & i).Value = FoundCell.Offset(, -3).Value
Sheets("Plan1").Range("upps0" & i).Value = FoundCell.Offset(, -1).Value
Set FoundCell = Sheets("BD").Columns(5).FindNext(After:=FoundCell)
Loop Until FoundCell.Address = FirstAddr Or i >= 4
End Sub
However, now I realize that I'll need more fields because I maybe insert more than 4 tecnicos on an alocacao. So now this is how it looks:
And I just changed this part of the code:
If FoundCell Is Nothing Then Exit Sub
Do
i = i + 1
Sheets("Plan1").Range("tecnico" & i).Value = FoundCell.Offset(, -3).Value
Sheets("Plan1").Range("upps0" & i).Value = FoundCell.Offset(, -1).Value
Set FoundCell = Sheets("BD").Columns(5).FindNext(After:=FoundCell)
Loop Until FoundCell.Address = FirstAddr Or i >= 10
So I was expecting that it just fills 4 fields as I still have only 4 matches, but I got this result:
As I'm new using Find and FindNext, I really don't know what I have to change to fill the cells with the matches only without repeating it.
Any suggestions will help! Maybe there is something I couldn't notice there.
I just used the suggestion of #Luuklag and now it's working.
Sub VerifProd_Click()
Dim FoundCell As Range, FirstAddr As String, fnd As String, i As Long
fnd = Sheets(1).Range("alocacao").Value
Set FoundCell = Sheets("BD").Columns(5).Find(what:=fnd, _
After:=Sheets("BD").Cells(Rows.Count, 5), Lookat:=xlPart, _
LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not FoundCell Is Nothing Then
FirstAddr = FoundCell.Address
End If
If FoundCell Is Nothing Then Exit Sub
Do
i = i + 1
Sheets("Plan1").Range("tecnico" & i).Value = FoundCell.Offset(, -3).Value
Sheets("Plan1").Range("upps0" & i).Value = FoundCell.Offset(, -1).Value
Set FoundCell = Sheets("BD").Columns(5).FindNext(After:=FoundCell)
Loop Until FoundCell.Address = FirstAddr Or i >= 10
End Sub
So I have a part in my macro that I want to add what I assume needs to be an "Else" portion, but I am not that good with macros and am asking for help.
Range("Z1").Copy
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Pull").Range("Y1").Value
If Trim(FindString) <> "" Then
With Sheets("HourTracker").Range("A:A")
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Application.Goto Rng, True
Else
MsgBox "Nothing found"
End If
End With
ActiveCell.Offset(0, 1).Activate
Selection.PasteSpecial xlPasteValues
Application.DisplayAlerts = True
End If
End Sub
So what I want this to do, is instead of "MsgBox "Nothing Found"", I want it to essentially perform the same thing as above, but copy cell Z2, and search for the value of Y2 in the same sheet "HourTracker" then paste the value. I have no idea on how to accomplish this, and all my attempts have failed. Any help would be much appreciated. Let me know if you need more clarification, thank you in advance!!!
Sounds to me like you're looking for a loop.
Sub findStuff()
Application.DisplayAlerts = False
' The item you want to paste
Dim PasteString As String
' The item you're looking for
Dim FindString As String
' The range that may containing FindString
Dim Rng As Range
' The variable used to loop through your range
Dim iCounter as Long
' loop through the first cell in column Y to the last used cell
For iCounter = 1 To Sheets("Pull").Cells(Rows.Count, 25).End(xlUp).Row
' PasteString = the current cell in column Z
PasteString = Sheets("Pull").Cells(iCounter, 26).Value
' FindString = the current cell in column Y
FindString = Sheets("Pull").Cells(iCounter, 25).Value
If Trim(FindString) <> "" Then
With Sheets("HourTracker").Range("A:A")
' Find the cell containing FindString
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
' There's no need to activate/ select the cell.
' You can directly set the value with .Value
Rng.Offset(0, 1).Value = PasteString
Else
' Do nothing
End If
End With
Else
' Do nothing
End If
Next
Application.DisplayAlerts = True
End Sub
Every time the compiler hits Next it will start again at For but raise the value of iCounter by 1. We can use Cells to accomplish this since Cells takes the row and column arguments as numbers, not strings (like Range). The syntax is simply Cells(Row #, Column #). Therefore, every time the For . . . Next loops around again, iCounter will go up by one and you'll search in the next row.
Instead of using .Paste, you can set the value of a cell directly with .Value. Pasting is pretty slow and using .Value is much faster.
Cells().End(xlUp).Row is a method used to find the last used cell in a range. See Error in finding last used cell in VBA for a much better explanation than I can give here.
I have the following nodes:
Expected output:
My current steps to get this are:
Delimit by "/"
Sort
Conditionally format some cells. I'm trying to make the cells blank by doing A2=A1 and setting the font color to white. However this is not working.
How can I do that using VBA? I am told that this would probably require VBA.
The trick is keeping only one of the parent nodes per line.
Try with formulas (in new sheet or column) like
X2 =IF(A2=A1,"",A2)
X3 =IF(A3=A2,"",A3)
X4 =IF(A4=A3,"",A4)
etc..
For column A
Quick and dirty, but it gets the job done. This will loop through columns A-F rows 1-12 and select the value for each cell find that occurrence and delete the second occurrence not the first. This should do the trick.
Sub findItemInColumns()
With ThisWorkbook.Worksheets("Sheet1")
For r = 1 To 12
For c = 1 To 6
RemoveDups .Cells(r, c).Value
Next
Next
End With
End Sub
Sub RemoveDups(ByVal somevalueToFindAndRemove As String)
Dim FindString As String
Dim Rng As Range
listOfValues = Array(somevalueToFindAndRemove)
If Trim(somevalueToFindAndRemove) <> "" Then
With Sheets("Sheet1").Range("A:AK")
For i = LBound(listOfValues) To UBound(listOfValues)
Set Rng = .Find(What:=listOfValues(i), _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Application.Goto Rng, True
If Rng.Address <> FirstAddress Then Rng.Value = ""
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
Next i
End With
End If
End Sub
I am trying to create a macro in excel VBA, that searches the Range (B1:B30) of the value of the ActiveCell in Column “B” by a loop. Along with the search of Column, I also want to check if the date’s cell is colored with a particular color. If the date's cell equals the set color "Good", then I want it to change the color of the cell in Column H of the same row as selected to red.
When I run the code, I get an error message of “Run-time error ‘424’: Object required.” When I go to debug the problem, it highlights the .Find function I have and points to the last line of the search which is “SearchFormat:=False).Activate” What should I do to fix this problem?
Any improvement with my overall code will be very much appreciated.
Sub Find()
Dim FirstAddress As String
Dim MySearch As Variant
Dim Rng As Range
Dim I As Long
MySearch = Array(ActiveCell)
With Sheets("Sheet1").Range("B1:B30")
For I = LBound(MySearch) To UBound(MySearch)
Set Rng = .Find(What:=MySearch(I), _
After:=ActiveCell, _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
SearchFormat:=False).Activate
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
If ActiveCell.Style.Name = "Good" Then
Rng("H" & ActiveCell.Row).Select
Rng.Interior.ColorIndex = xlColorIndexRed
End If
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
Next I
End With
End Sub
Showing the Debug mode of the run-time error.
Screenshot of the Spreadsheet for reference
Code Review:
You have several problems here.
MySearch = Array(ActiveCell) will always be a single value. So why bother looping through it
You cannot set a range to equal range.activate. Searching Sheets("Sheet1").Range("B1:B30") implies that you are searching a worksheet other that the ActiveSheet. If this is the case than .Find(After:=Activecell) suggests that you are looking for a value after the ActiveCell of another worksheet.
Set Rng = .Find(What:=MySearch(I), _
After:=ActiveCell, _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
SearchFormat:=False).Activate
Rng("H" & ActiveCell.Row) Rng is a Range object. It doesn't work like Range. You cannot pass it a cell address. You can do this Rng(1,"H") which is really shorthand for Rng.cells(1,"H") bit that is misleading because Rng is in column 2 Rng(1,"H") will reference the value in column I.
Sub Find()
Dim FirstAddress As String
Dim MySearch As Variant
Dim Rng As Range
Dim I As Long
MySearch = ActiveCell 'This is the ActiveCell of the ActiveSheet not necessarily Sheets("Sheet1")
With Sheets("Sheet1").Range("B1:B30")
Set Rng = .Find(What:=MySearch, _
After:=.Range("B1"), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
SearchFormat:=False)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
If Rng.Style.Name = "Good" Then
.Range("H" & Rng.Row).Interior.ColorIndex = xlColorIndexRed
End If
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
End With
End Sub
UPDATE:
Here is the actual answer to your question:
Sub FindMatchingValue()
Const AllUsedCellsColumnB = False
Dim rFound As Range, SearchRange As Range
If AllUsedCellsColumnB Then
Set SearchRange = Range("B1", Range("B" & Rows.count).End(xlUp))
Else
Set SearchRange = Range("B1:B30")
End If
If Intersect(SearchRange, ActiveCell) Is Nothing Then
SearchRange.Select
MsgBox "You must select a cell in the highlighted area before continuing", vbInformation, "Action Cancelled"
Exit Sub
End If
Set rFound = SearchRange.Find(What:=ActiveCell.Value, _
After:=ActiveCell, _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
SearchFormat:=False)
If Not rFound Is Nothing Then
Do
If rFound.Style.Name = "Good" Then
Range("H" & rFound.Row).Interior.Color = vbRed
End If
Set rFound = SearchRange.FindNext(rFound)
Loop While Not rFound Is Nothing And rFound.Address <> ActiveCell.Address
End If
End Sub
You can't put Activate at the end of the findthe way you are trying to do.
Try this as you find statement.
Set Rng = .Find(What:=MySearch(I), _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
Rng.Activate
Then if you want to Activate the range, do that. But, it is best to stay away from Select, Activate etc in VBA code. I strongly suggest not using that last line of code and adjust you code to not rely on Select and Activate.
you may want to consider an Autofilter approach so as to loop only through relevant cells, as follows:
Option Explicit
Sub Find()
Dim cell As Range
With Sheets("Sheet1").Range("B1:B30")
.Rows(1).Insert '<--| insert a dummy header cell to exploit Autofilter. it'll be removed by the end
With .Offset(-1).Resize(.Rows.Count + 1) '<--| consider the range expanded up to the dummy header cell
.Rows(1) = "header" '<--| give the dummy header cell a dummy name
.AutoFilter field:=1, Criteria1:=ActiveCell '<--| filter range on the wanted criteria
If Application.WorksheetFunction.Subtotal(103, .Cells) > 1 Then '<--| if any cell other than "header" one has been filtered...
For Each cell In .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) '<--| ... loop through filtered cells only
If cell.Style.Name = "Good" Then cell.Offset(, 6).Interior.ColorIndex = 3 '<--| ... and color only properly styled cells
Next cell
End If
.AutoFilter '<--| .. show all rows back...
End With
.Offset(-1).Resize(1).Delete '<--|delete dummy header cell
End With
End Sub
Here's my code:
Need my code to enter TRUE in a cell if it finds a value in column A of sheet "Itemschedule" to be present in column B of sheet "Whereused". Getting "Type mismatch" error. If I change the "st = Sheets(..." line to .Value instead of .Text, or if I change the .Find line to LookIn:=xlFormulas instead of Lookin:=xlValues, it gives the same error irrespective of the combination of the two.
Private Sub CommandButton1_Click()
Dim rowLast As Integer
Dim str As String
Dim cell As Range
Sheets("Itemschedule").ListObjects("Table2").Range.AutoFilter
rowLast = Sheets("Itemschedule").Cells(Rows.Count, "A").End(xlUp).Row
Sheets("Itemschedule").ListObjects("Table2").Resize Range("A1:E" & rowLast)
Sheets("Itemschedule").Range("A" & rowLast + 1 & ":E" & Rows.Count).ClearContents
For i = 2 To rowLast
str = Sheets("Itemschedule").Cells(i, "A").Text
With Sheets("Whereused").Range("B:B")
Set cell = .Find(What:=str, After:=.Range("B1"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
End With
If cell Is Nothing Then
Sheets("Itemschedule").Cells(i, "E").Value = "FALSE"
Else
Sheets("Itemschedule").Cells(i, "E").Value = "TRUE"
End If
Next
On Error Resume Next
Sheets("Itemschedule").ListObjects("Table2").Range.AutoFilter
Sheets("Itemschedule").Range("A1:E" & rowLast).AutoFilter Field:=1, Criteria1:="FALSE"
Sheets("Itemschedule").Range("A1:E" & rowLast).SpecialCells(xlCellTypeVisible).EntireRow.Delete
Sheets("Itemschedule").ListObjects("Table2").Resize Range("A1:E" & rowLast)
Sheets("Itemschedule").ListObjects("Table2").Range.AutoFilter
End Sub
I have tried a lot but am not able to figure it out. I'm sure it's something silly.
Please help.
Your error is due to the fact that the After parameter is not inside the range you are searching. This part:
With Sheets("Whereused").Range("B:B")
Set cell = .Find(What:=str, After:=.Range("B1"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
End With
should be:
With Sheets("Whereused").Range("B:B")
Set cell = .Find(What:=str, After:=Sheets("Whereused").Range("B1"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
End With
otherwise the .Range("B1") is relative to Range("B:B") and therefore refers to C1.
Dictionaries are more efficient at finding duplicate values.
Sub CommandButton1_Click()
Dim keyword As String, keyvalue As Variant
Dim rowLast As Long, x As Long
Dim dicItems
Set dicItems = CreateObject("scripting.dictionary")
With Sheets("Whereused")
rowLast = .Cells(Rows.Count, "A").End(xlUp).Row
For x = 2 To rowLast
keyword = .Cells(x, 2)
keyvalue = .Cells(x, 2)
'Add Key Value pairs to Dictionary
If Not dicItems.Exists(keyword) Then dicItems.Add keyword, keyvalue
Next
End With
With Sheets("Itemschedule")
rowLast = .Cells(Rows.Count, "A").End(xlUp).Row
For x = 2 To rowLast
keyword = .Cells(x, 1)
.Cells(x, 2) = dicItems.Exists(keyword)
Next
End With
End Sub
But the proper way to do it place a WorkSheet Formula in Itemschedule Column B.
=COUNTIF(Table1[[#This Row],[Items]],Table2[[#Headers],[Items]])>0