populate listbox with specific rows from an excel sheet - vba

I have an excel sheet named ("PPSBoarded") with 15 columns. I want to select rows based on similar values in column B and then display it in listbox on a VBA form. I tried this but it's not working:
Dim FoundCell As Range
Dim LastCell As Range
Dim FirstAddr As String
With Range("B1:B2")
Set LastCell = .Cells(.Cells.Count)
End With
Set FoundCell = Range("B1:B").Find(what:="EK261/GRU", after:=LastCell)
If Not FoundCell Is Nothing Then
FirstAddr = FoundCell.Address
End If
Do Until FoundCell Is Nothing
Debug.Print FoundCell.Address
Set FoundCell = Range("B1:B").FindNext(after:=FoundCell)
If FoundCell.Address = FirstAddr Then
Exit Do
End If
Loop
Me.ListBox1.List = FirstAddr

Your code should look like this:
Dim arrLstBox()
Dim rng, FoundCell, tmpCell As Range
Dim i, j, numRows, lastColumn, lastRow As Long
Dim FirstAddress, searchFor, colWidth As String
Set rng = ActiveSheet.UsedRange
numRow = 0
With rng
lastRow = .Rows.Count
lastColumn = .Columns.Count
End With
Me.ListBox1.ColumnCount = lastColumn
For x = 1 To lastColumn
If x = lastColumn Then
colWidth = colWidth & "1,5cm"
Exit For
End If
colWidth = colWidth & "1,5cm;"
Next x
Me.ListBox1.ColumnWidths = colWidth
searchFor = InputBox("Your word:")
Set FoundCell = rng.Find(what:=searchFor)
If Not FoundCell Is Nothing Then _
FirstAddress = FoundCell.Address
Do Until FoundCell Is Nothing
Set FoundCell = rng.FindNext(after:=FoundCell)
If FoundCell.Address = FirstAddress Then
numRow = numRow + 1
Exit Do
ElseIf FoundCell.Row <> rng.FindNext(after:=FoundCell).Row Then
numRow = numRow + 1
End If
Loop
ReDim arrLstBox(1 To numRow, 1 To lastColumn)
Do Until FoundCell Is Nothing
For i = 1 To numRow
For j = 1 To lastColumn
If Not IsEmpty(Cells(FoundCell.Row, j).Value) Then
arrLstBox(i, j) = Cells(FoundCell.Row, j).Value
End If
Set FoundCell = rng.FindNext(after:=FoundCell)
Next j
If FoundCell.Address = FirstAddress Then _
Exit For
Next i
If FoundCell.Address = FirstAddress Then _
Exit Do
Loop
Me.ListBox1.List = arrLstBox()

Related

Find and FindNext to copy data corresponding to all matches

I want to search Column 5 on sheet "BD" for all the entries that match a value called "alocacao" on my sheet "Plan1".
Then copy the value on Column 2 to the cell called "tecnico1" (the other cells are called "tecnico2, tecnico3 and tecnico4").
The cell with the value TESTE 2 is the "alocacao".
I tried Find and FindNext:
Sub VerifProd_Click()
Dim FoundCell As Range
Dim LastCell As Range
Dim FirstAddr As String
Dim fnd As String
Dim i As Long
i = 2
fnd = Sheets(1).Range("alocacao").Value
With Sheets("BD").Columns(5)
Set LastCell = .Cells(.Cells.Count)
End With
Set FoundCell = Sheets("BD").Columns(5).Find(what:=fnd, after:=LastCell)
If Not FoundCell Is Nothing Then
FirstAddr = FoundCell.Address
End If
Do Until FoundCell Is Nothing
Sheets("BD").Cells(i,2).Copy Sheets("Plan1").Range("tecnico" & i).Value
i = i + 1
Set FoundCell = Sheets("BD").Columns(5).FindNext(after:=FoundCell)
If FoundCell.Address = FirstAddr Then
Exit Do
End If
Loop
End Sub
I get
Run-time error 1004
but the code is not highlighted.
EDIT
I changed a part of it to test if it will paste the value on cell B26.
Now I get
Run-time error 438
With Sheets("BD").Columns(5)
Set LastCell = .Cells(.Cells.Count)
End With
Set FoundCell = Sheets("BD").Columns(5).Find(what:=fnd, after:=LastCell)
If Not FoundCell Is Nothing Then
FirstAddr = FoundCell.Address
End If
Do Until FoundCell Is Nothing
Sheets("Plan1").Range("B26") = FoundCell.Adress.Offset(0, -3).Value
Set FoundCell = Sheets("BD").Columns(5).FindNext(after:=FoundCell)
If FoundCell.Address = FirstAddr Then
Exit Do
End If
Loop
Ok supposing you have 4 named cells in sheet "Plan1" with names tecnico1, tecnico2, tecnico3 and tecnico4, I suggest the following modification, having in mind that we should stop at 4 matches which the number of named ranges tecnico:
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
FirstAddr = FoundCell.Adress
Do
i = i + 1
Sheets("Plan1").Range("tecnico" & i).value = FoundCell.Offset(,-3).Value2
Set FoundCell = Sheets("BD").Columns(5).FindNext(After:=FoundCell)
Loop Until FoundCell.Address = FirstAddr Or i >= 4
End Sub
.Find and .FindNext algorithm is used like below...
With Sheets("BD").Columns(5)
Set FoundCell = .Find(what:=fnd, after:=LastCell)
If Not FoundCell Is Nothing Then
FirstAddr = FoundCell.Address
Do
Sheets("BD").Cells(i, 2).Copy Sheets("Plan1").Range("tecnico" & i).Value
i = i + 1
Set FoundCell = .FindNext(FoundCell)
Loop While Not FoundCell Is Nothing And FirstAddr <> FoundCell.Address
End If
End With

Modify macro for column search

I have a macro that until now was used just to search one cell from column F but now I must search for all the cell in column F. If value from F is found in range N:AN, offset(f,0,1) must have the cell value (found row , column AI).
Sub find()
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Sheet1").Range("f48").Value
If Trim(FindString) <> "" Then
With Sheets("Sheet1").Range("n:an")
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
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = Rng.Offset(0, 21).Value
Else
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
End Sub
Perhaps this, if I understand correctly (it does assume the value in F will only be found once at most).
Sub find()
Dim Rng As Range
Dim r As Range
With Sheets("Sheet1")
For Each r In .Range("F1", .Range("F" & .Rows.Count).End(xlUp))
If Trim(r) <> vbNullString Then
With .Range("n:an")
Set Rng = .find(What:=r.Value, _
LookAt:=xlWhole, _
MatchCase:=False)
If Not Rng Is Nothing Then
r.Offset(0, 1).Value = .Cells(Rng.Row, "AI").Value
'Else
' Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
Next r
End With
End Sub
See if this is helpful. Its a bit of a change but I think it may be cleaner :)
Of course you need to adjust it for your offset criteria once you "find" a match in the N:NA range
Sub Dougsloop()
Dim rCell As Range
Dim rRng As Range
Dim wsO As Worksheet
Dim aRR As Variant
Set wsO = ThisWorkbook.Sheets("Sheet1")
aRR = wsO.UsedRange.Columns("N:NA")
Set rRng = ThisWorkbook.Sheets("Sheet1").Range("F1:F500")
For Each rCell In rRng.Cells
If Trim(rCell.Value) <> vbNullString Then
thisValue = rCell.Value
If IsError(Application.Match(aRR, thisValue, 0)) = True Then
'Generic Eror Handling
ElseIf IsError(Application.Match(aRR, thisValue, 0)) = False Then
'Stuff you do when you find the match
rCell.Offset(0, 1).Value = "found it"
End If
End If
Next rCell
End Sub

using vlookup to find matching values in a column

I have a column A with duplicate values inside it. I want to write a vlookup which does the following; If A has duplicate value inside it, the B value of this columns same row should be overwritten to previous A values same row in Column B.
An example for this ;
A B
1 Anna | 23 years old
2 Anna | 34 years old
So the value in B1 should be automatically 34 years old since the values in A column match.
How can i do this?
Try this:
Sub Demo()
Dim dict1 As Object
Dim c1 As Variant
Dim i As Long, lastRow As Long
Dim strFound As Range
Dim strFirst As String, copyVal As String
Set dict1 = CreateObject("Scripting.Dictionary")
lastRow = Cells(Rows.Count, "A").End(xlUp).Row '-->get last row with data in column A
'enter unique values of column A in dict1
c1 = Range("A1:A" & lastRow)
For i = 1 To UBound(c1, 1)
dict1(c1(i, 1)) = 1
Next i
For Each k In dict1.keys
'find last occurrence of each value in dict1
Set rngFound = Columns("A").Find(k, Cells(Rows.Count, "A"), xlValues, xlWhole, , xlPrevious)
If Not rngFound Is Nothing Then
'get column B value for found string
copyVal = rngFound.Offset(0, 1).Value
strFirst = rngFound.Address
Do
'find all the occurrences of each value in dict1
Set rngFound = Columns("A").Find(k, rngFound, xlValues, xlWhole, , xlPrevious)
'change value in column B for each occurrence
rngFound.Offset(0, 1).Value = copyVal
Loop While rngFound.Address <> strFirst
End If
Next k
End Sub
See image for reference:
EDIT# 1
________________________________________________________________________________
Sub Demo()
Application.ScreenUpdating = False
Dim dict1 As Object, dict2 As Object
Dim c1 As Variant
Dim i As Long, lastRow As Long
Dim strFound As Range, delRange As Range
Dim strFirst As String, copyVal As String
Set dict1 = CreateObject("Scripting.Dictionary")
Set dict2 = CreateObject("Scripting.Dictionary")
lastRow = Cells(Rows.Count, "A").End(xlUp).Row '-->get last row with data in column A
'enter unique values of column A in dict1
c1 = Range("A1:A" & lastRow)
For i = 1 To UBound(c1, 1)
dict1(c1(i, 1)) = 1
Next i
For Each k In dict1.keys
'find last occurrence of each value in dict1 and save row number in dict2
Set rngFound = Columns("A").Find(k, , xlValues, xlWhole, , xlPrevious)
If Not rngFound Is Nothing Then
dict2.add rngFound.Row, 1
End If
Next k
'check for column A if row number exists in dict2, if not then add to a range for deletion
For i = 1 To lastRow
If Not dict2.exists(Cells(i, 1).Row) Then
Debug.Print Cells(i, 1).Address
If delRange Is Nothing Then
Set delRange = Cells(i, 1)
Else
Set delRange = Union(delRange, Cells(i, 1))
End If
End If
Next i
'delete the range
If Not delRange Is Nothing Then
delRange.EntireRow.Delete
End If
Application.ScreenUpdating = True
End Sub
EDIT# 2
________________________________________________________________________________
Sub Demo()
Application.ScreenUpdating = False
Dim dict1 As Object, dict2 As Object
Dim c1 As Variant
Dim i As Long, lastRow As Long
Dim strFound As Range, delRange As Range
Dim rngFound As Range, rngFound1 As Range
Dim strFirst As String, copyVal As String
Set dict1 = CreateObject("Scripting.Dictionary")
Set dict2 = CreateObject("Scripting.Dictionary")
lastRow = Cells(Rows.Count, "B").End(xlUp).Row '-->get last row with data in column A
'enter unique values of column A in dict1
c1 = Range("B1:B" & lastRow)
For i = 1 To UBound(c1, 1)
dict1(c1(i, 1)) = 1
Next i
For Each k In dict1.keys
'find first occurrence of each value in dict1
Set rngFound = Columns("B").Find(k, , xlValues, xlWhole)
'find last occurrence of each value in dict1
Set rngFound1 = Columns("B").Find(k, , xlValues, xlWhole, , xlPrevious)
If rngFound.Address <> rngFound1.Address Then
rngFound.Offset(0, 1) = rngFound1.Offset(0, 1)
rngFound.Offset(0, 2) = rngFound1.Offset(0, 2)
If delRange Is Nothing Then
Set delRange = rngFound1
Else
Set delRange = Union(delRange, rngFound1)
End If
End If
Next k
'delete the range
If Not delRange Is Nothing Then
delRange.EntireRow.Delete
End If
Application.ScreenUpdating = True
End Sub

Conditional loop with running sum is skipping values

I have created this code with the purpose of:
First Loop:
Loop through cells in column O to find anything that starts with DAAP.
If Cell 5 columns left of DAAP is empty then add the cell 1 column to the right (which is a number) to Total. Then rename the cell to GAAF
If Cell 5 columns left is not empty then just rename the cell to GAAF
Second Loop:
Find all GAAF cells in column O and then change the cell 1 column to the right to Total
Here is the code I have, it runs with no errors but just does nothing. I'm assuming something is syntax'ed wrong so it's looking in the wrong place but I can't find it! Any help is greatly appreciated :)
Dim rng As Range
Dim lstRow As Long
Dim AUMCell As Range
Dim Total As Long
lstRow = Cells(Rows.Count, "O").End(xlUp).Row
Set rng = Range("O2", Cells(lstRow, "O"))
Total = 0
For Each AUMCell In rng
If AUMCell.value = "DAAP" & "*" And AUMCell.Offset(0, -5).value = "" Then
Total = Total + AUMCell.Offset(0, 1).Value
AUMCell.value = "GAAF"
ElseIf AUMCell.value = "DAAP" & "*" And AUMCell.Offset(0, -5).value <> "" Then
AUMCell.value = "GAAF"
End If
Next AUMCell
For Each AUMCell In rng
If AUMCell.Value = "GAAF" Then
AUMCell.Offset(0, 1).Value = Total
End If
Next AUMCell
While the code is longer the execution of Find will be much quicker than a loop through each cell.
Sub Recut()
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim aCell As Range
Dim bCell As Range
Dim ws As Worksheet
Dim SearchString As String
Set ws = ActiveSheet
Set rng1 = ws.Range("O:O")
SearchString = "DAAP"
Set aCell = rng1.Find(SearchString, , xlFormulas, xlPart, xlByRows, xlNext)
If Not aCell Is Nothing Then
Set bCell = aCell
If Left$(aCell.Value, 4) = SearchString Then Set rng2 = aCell
Do
Set aCell = rng1.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
If Left$(aCell.Value, 4) = SearchString Then
If Not rng2 Is Nothing Then
Set rng2 = Union(rng2, aCell)
Else
Set rng2 = aCell
End If
End If
Else
Exit Do
End If
Loop
Else
MsgBox SearchString & " not Found"
Exit Sub
End If
If rng2 Is Nothing Then Exit Sub
For Each rng3 In rng2
If Len(rng3.Offset(0, -5)) = 0 Then Total = Total + rng3.Offset(0, 1).Value
rng3.Value = "GAFF"
Next
MsgBox Total
End Sub
Try to replace this code
For Each AUMCell In rng
If AUMCell.value = "DAAP" & "*" And AUMCell.Offset(0, -5).value = "" Then
Total = Total + AUMCell.Offset(0, 1).Value
AUMCell.value = "GAAF"
ElseIf AUMCell.value = "DAAP" & "*" And AUMCell.Offset(0, -5).value <> "" Then
AUMCell.value = "GAAF"
End If
Next AUMCell
by this code
For Each AUMCell In rng
If AUMCell.value like "DAAP*" Then
If AUMCell.Offset(0, -5).value = "" Then
Total = Total + AUMCell.Offset(0, 1).Value
End If
AUMCell.value = "GAAF"
End If
Next AUMCell
P.S.: Sorry my english

Filter in Excel VBA

I have a loop in VBA that loops through about 3000+ records and hides the ones that don't fit the criteria. It works just fine but it runs SUPER slow. Is there a faster or more efficient way to filter based on the following criteria? Any help would be greatly appreciated.
Dim i As Long, rng1 As Range, rng2 As Range, rng3 As Range, rng4 As Range, rng5 As Range, j As Long, sheetName As String, rng6 As Range, rng7 As Range, rng8 As Range, rng9 As Range
Set rng1 = FindHeader("Client Exclusion List", Sheet8.Name)
Set rng2 = FindHeader("CLIENT NAME", Sheet5.Name)
Set rng3 = FindHeader("MARKET SEGMENT", Sheet5.Name)
Set rng4 = FindHeader("ARCHIVED", Sheet5.Name)
Set rng5 = FindHeader("FORMULARY NAME", Sheet5.Name)
Set rng6 = FindHeader("WEBSITE", Sheet5.Name)
Set rng7 = FindHeader("PDF", Sheet5.Name)
Set rng8 = FindHeader("HPMS EXPORTED", Sheet5.Name)
Set rng9 = FindHeader("SERFF EXPORTED", Sheet5.Name)
For i = 1 To rng2.Rows.Count
'Checks to see if the Client Name is in the Excluded list
For j = 1 To rng1.Rows.Count
If rng2.Cells(i, 1).Value = rng1.Cells(j, 1).Value Then
rng2.Cells(i, 1).EntireRow.Hidden = True
End If
Next j
'Checks For all CMS records and hides the ones that are not from current year
If Left(rng3.Cells(i, 1).Value, 8) = "CMS Part" Then
If rng3.Cells(i, 1).Value <> "CMS Part D (CY " & Year(Date) & ")" Then
rng3.Cells(i, 1).EntireRow.Hidden = True
End If
End If
'Checks if record is archived
If rng4.Cells(i, 1).Value = "Yes" Then
rng4.Cells(i, 1).EntireRow.Hidden = True
End If
'Checks if record contains "Test" or "Demo" in the Name
If InStr(1, CStr(rng5.Cells(i, 1).Value), "test") > 0 Or InStr(1, CStr(rng5.Cells(i, 1).Value), "Test") > 0 Or InStr(1, CStr(rng5.Cells(i, 1).Value), "demo") > 0 Or InStr(1, CStr(rng5.Cells(i, 1).Value), "Demo") > 0 Or InStr(1, CStr(rng5.Cells(i, 1).Value), "TEST") > 0 Or InStr(1, CStr(rng5.Cells(i, 1).Value), "DO NOT USE") > 0 Then
rng5.Cells(i, 1).EntireRow.Hidden = True
End If
Next i
Here's an example that should be faster. It uses array, autofilter and doesn't process all the other ranges for each row of rng2:
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim rng4 As Range
Dim rng5 As Range
Dim rng6 As Range
Dim rng7 As Range
Dim rng8 As Range
Dim rng9 As Range
Dim i As Long
Dim j As Long
Dim sheetName As String
Dim vData1
Set rng1 = FindHeader("Client Exclusion List", Sheet8.Name)
Set rng2 = FindHeader("CLIENT NAME", Sheet5.Name)
Set rng3 = FindHeader("MARKET SEGMENT", Sheet5.Name)
Set rng4 = FindHeader("ARCHIVED", Sheet5.Name)
Set rng5 = FindHeader("FORMULARY NAME", Sheet5.Name)
Set rng6 = FindHeader("WEBSITE", Sheet5.Name)
Set rng7 = FindHeader("PDF", Sheet5.Name)
Set rng8 = FindHeader("HPMS EXPORTED", Sheet5.Name)
Set rng9 = FindHeader("SERFF EXPORTED", Sheet5.Name)
Application.ScreenUpdating = False
vData1 = rng1.Value
For i = 1 To rng2.Rows.Count
'Checks to see if the Client Name is in the Excluded list
For j = LBound(vdata1, 1) To UBound(vdata1, 1)
If rng2.Cells(i, 1).Value = vdata1(j, 1) Then
rng2.Cells(i, 1).EntireRow.Hidden = True
Exit For
End If
Next j
Next i
'Checks For all CMS records and hides the ones that are not from current year
rng3.AutoFilter 1, "<>CMS Part*", xlOr, "CMS Part D (CY " & Year(Date) & ")"
'Checks if record is archived
rng4.AutoFilter 1, "<>Yes"
'Checks if record contains "Test" or "Demo" in the Name
rng5.AutoFilter 1, "<>*test*", xlAnd, "<>*demo*"
Application.ScreenUpdating = True
One small change that should help is adding
Application.ScreenUpdating = False
at the beginning and
Application.ScreenUpdating = True
at the end
The screen updating time can be much more substantial than the logic.
Edit as an alternative to the array loop. Creates a dictionary filled with the excluded items as keys before the big loop. A set would be better here since you have a useless item to go with each key but I don't think VBA has those.
Instead of the loop through the range or an array you just check for the existence of the key in the dictionary.
'before loop
Dim excludedList As Object
Set excludedList = CreateObject("Scripting.Dictionary")
For i = 1 To rng1.Rows.Count
excludedList.Add rng1.Cells(i, 1).value, 1
Next i
'****************************************
'in loop
If excludedList.exists(rng2.Cells(i, 1).Value) Then
rng2.Cells(i, 1).EntireRow.Hidden = True
End If