Using an array to search active sheet - arrays

I have a worksheet which is updated regularly with details of duplicate records from a database.
I am trying to create a macro which searches for particular records however as I am new to Excel VBA I am struggling.
The code I currently have is as follows:
there are more names (21 to be precise but to save time I have removed these)
Dim rg As Range
Dim lnglastrow As Long
Dim intnamemax As Integer
Dim strName() As String
intnamemax = 21
ReDim strName(1 To intnamemax)
strName(1) = "Bob Smith"
strName(2) = "Rhys Jones"
strName(3) = "Rebecca Hickling"
lnglastrow = ActiveSheet.UsedRange.Rows.Count
For Each rg In Range("A2:A" & lnglastrow)
For i = 1 To intnamemax
Set c = rg.Find(strName(i), LookIn:=xlValues)
If Not c Is Nothing Then
MsgBox "Proxy Candidate Found at " & found.Address
Else
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
Next i
Next
End Sub
the Macro will run however when testing I get the msgbox no proxy candidates found despite there being an entry for one of the names.
I am struggling to figure out where I have gone wrong and would appreciate any help.

You need to pull the false return out of the loop, Or you will get at least 20 false even if one matches.
And you do not need the exterior loop as the FIND will look at the whole range as one.
Dim lnglastrow As Long
Dim intnamemax As Integer
Dim strName() As String
Dim fnd As Boolean
intnamemax = 21
ReDim strName(1 To intnamemax)
strName(1) = "Bob Smith"
strName(2) = "Rhys Jones"
strName(3) = "Rebecca Hickling"
lnglastrow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To intnamemax
Set c = Range("A2:A" & lnglastrow).Find(strName(i), LookIn:=xlValues)
If Not c Is Nothing Then
MsgBox "Proxy Candidate Found at " & c.Address
fnd = True
Exit For
End If
Next i
If Not fnd Then
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
End Sub

Related

Subscript out of range when trying to loop through array to read values

I have a string of predefined worksheets, that I need to run specific code for. I get a compile error.
The code is set up to copy data from one sheet to another.
How do I do the same for multiple sheets?
When I step through the code sht is showing the MHP60,MHP61,MHP62 and not just MHP60.
I get a subscript out of range error.
Sub Prepare_CYTD_Report()
Dim addresses() As String
Dim addresses2() As String
Dim SheetNames() As String
Dim SheetNames2() As String
Dim wb1 As Workbook, wb2 As Workbook
Dim my_Filename
'Declare variables for MHP60, MHP61, MHP62 Trial Balance Values
Dim i, lastcol As Long
Dim tabNames, cell As Range
Dim tabName As String
Dim sht As Variant
addresses = Strings.Split("A9,A12:A26,A32:A38,A42:A58,A62:A70,A73:A76,A83:A90", ",") 'Trial Balance string values
addresses2 = Strings.Split("G9,G12:G26,G32:G38,G42:G58,G62:G70,G73:G76,G83:G90", ",") 'Prior Month string values
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
'SheetNames2 = Strings.Split("MHP60-CYTDprior,MHP61-CYTDprior,MHP62-CYTDprior")
Set wb1 = ActiveWorkbook 'Revenue & Expenditure Summary Workbook
'*****************************Open CYTD files
my_Filename = Application.GetOpenFilename(fileFilter:="Excel Files,*.xl*;*.xm*", Title:="Select File to create CYTD Reports")
If my_Filename = False Then
Exit Sub
End If
Application.ScreenUpdating = False
Set wb2 = Workbooks.Open(my_Filename)
'*****************************Load Column Header Strings & Copy Data
For Each sht In SheetNames
lastcol = wb1.Sheets(sht).Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames = wb1.Sheets(sht).Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP60", vbCritical
Exit Sub
End If
For Each cell In tabNames
tabName = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets(sht).Evaluate("ISREF('[" & wb2.Name & "]" & tabName & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName).Range(addresses(i)).Value2 = wb1.Sheets(sht).Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName & " was not found in " & wb2.Name
End If
Next cell
Next sht
MsgBox "CYTD Report Creation Complete", vbOKOnly
Application.ScreenUpdating = True
End Sub
Split by what?
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
Split by comma? Then use the following instead:
SheetNames = Strings.Split("MHP60,MHP61,MHP62", ",")
Alternative
Dim SheetNames() As Variant ' needs to be Variant to work with Array()
SheetNames = Array("MHP60", "MHP61", "MHP62")
This should be quicker as your macro does not need to split the string and has it as array directly.

shortcut to amend values in one column according to criteria in another

I'm New to VBA and finding my way around. I'm writing a macro which searches column 6 for postage method and enters the correct postage price (which often changes) in column 14.
I've started to use 'if statements' and it's working. However there are a total of 28 postage methods (and that could increase a few) I know there are shortcuts. I'm thinking this could possibly be done in an array which I could later edit as price changes
Sub Amend()
Application.ScreenUpdating = False
Dim row As Integer
Dim Lastrow As Long
Lastrow = Sheets(2).Cells(Rows.Count, "D").End(xlUp).row
If Lastrow > 1 Then
For row = 2 To Lastrow
'postage
If Sheets(2).Cells(row, 6).Value = "Austria Tracked" Then
Sheets(2).Cells(row, 14).Value = 4.79
End If
If Sheets(2).Cells(row, 6).Value = "International DDU shipments" Then
Sheets(2).Cells(row, 14).Value = 4.27
End If
If Sheets(2).Cells(row, 6).Value = " Landmark Belgium DDU" Then
Sheets(2).Cells(row, 14).Value = 4.27
End If
If Sheets(2).Cells(row, 6).Value = "France Untracked" Then
Sheets(2).Cells(row, 14).Value = 2.42
End If
If Sheets(2).Cells(row, 6).Value = "GLS France" Then
Sheets(2).Cells(row, 14).Value = 5.27
End If
I want to keep it simple but should I be using an array or a vlookup?
Multiple Criteria Lookup
Copy the code into a standard module (e.g. Module1).
Adjust the values in the constants section.
For each Method you add, you have to add the Price in the same position.
The Code
Option Explicit
Sub Amend()
Const Proc As String = "Amend"
On Error GoTo cleanError
' Define Constants.
Const SheetNameOrIndex As Variant = 2 ' Sheet Name is safer than index.
Const FirstRow As Long = 2
Const MethodColumn As Variant = 6 ' e.g. 6 or "F"
Const PriceColumn As Variant = 14 ' e.g. 14 or "N"
Dim MethodValue As Variant, PriceValue As Variant
MethodValue = Array("Austria Tracked", _
"International DDU shipments", _
"Landmark Belgium DDU", _
"France Untracked", _
"GLS France")
PriceValue = Array(4.79, _
4.27, _
4.27, _
2.42, _
5.27)
' Check if MethodValue and PriceValue Arrays have the same number
' of elements (columns).
Dim ubV As Long: ubV = UBound(MethodValue)
If UBound(PriceValue) <> ubV Then Exit Sub
' Copy values of Method and Price Columns to Method and Price Arrays.
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets(SheetNameOrIndex)
Dim rng As Range
Set rng = ws.Columns(MethodColumn).Find("*", , xlValues, , , xlPrevious)
If rng Is Nothing Then Exit Sub
If rng.Row < FirstRow Then Exit Sub
Dim Method As Variant
Method = ws.Range(ws.Cells(FirstRow, MethodColumn), rng).Value
Set rng = Nothing
Dim ubMP As Long: ubMP = UBound(Method)
Dim Price As Variant
Price = ws.Cells(FirstRow, PriceColumn).Resize(ubMP).Value
' Modify values in Price Array.
Dim i As Long, j As Long
For i = 1 To ubMP
For j = 0 To ubV
If Method(i, 1) = MethodValue(j) Then
Price(i, 1) = PriceValue(j)
Exit For
End If
Next j
Next i
Erase Method
' Write values of Price Array to Price Range.
ws.Cells(FirstRow, PriceColumn).Resize(ubMP).Value = Price
' Inform user.
MsgBox "Data copied.", vbInformation, "Success"
Exit Sub
cleanError:
MsgBox "An unexpected error occurred in '" & Proc & "'." & vbCr _
& "Run-time error '" & Err.Number & "':" & vbCr & Err.Description _
, vbCritical, Proc & " Error"
End Sub
Try the next code, please. You only must maintain arrPrices array. Each product must be separated by a comma, and product to be separated by its price using "|". You can extend the array as you need. The array can also be loaded on the fly if you will have two rows in a sheet keeping the product name on first and the price on the second:
Sub Amend()
Dim sh As Worksheet, row As Long, El As Variant, Lastrow As Long, arrPrices As Variant
Dim arrInt As Variant
Set sh = ActiveSheet ' use here your sheet
Lastrow = sh.Sheets(2).Cells(Rows.count, "D").End(xlUp).row
arrPrices = Split("Austria Tracked|4.79,International DDU shipments|1.27,Landmark Belgium DDU|4.27,France Untracked|2.42,GLS France|5,27", ",")
Application.ScreenUpdating = False
If Lastrow > 1 Then
For row = 2 To Lastrow
For Each El In arrPrices
arrInt = Split(El, "|")
If Sheets(2).Cells(row, 6).value = arrInt(0) Then
sh.Sheets(2).Cells(row, 14).value = arrInt(1)
Exit For
End If
Next
Next row
End If
Application.ScreenUpdating = True
End Sub
I used your code like model, but take care, please: You calculate the last row for column D:D and process the date in column 6 (F:F). Please, check and be sure that the last row calculation is appropriate and correlate them if necessary...
I supposed that each product may appear only once during iteration. Is this assumption correct?

Using an array to search active sheet

I have a worksheet which is updated regularly with details of duplicate records from a database.
I am trying to edit our current macro which searches for particular records however as I am new to Excel VBA I am struggling.
The macro works great however it only returns the cell reference for each ID number once. I am struggling to work out how to get it to return every cell reference for every time the specified ID number is listed.
The code I currently have is as follows (there are more ID numbers in the code but to save time I have removed these):
Sub IDSearch()
'
Dim rg As Range
Dim lnglastrow As Long
Dim intnamemax As Integer
Dim strName() As String
Dim fnd As Boolean
intnamemax = 42
ReDim strName(1 To intnamemax)
strName(1) = "OR123456"
strName(2) = "C00123456"
strName(3) = "UK123456"
lnglastrow = ActiveSheet.UsedRange.Rows.Count
For I = 1 To intnamemax
Set c = Range("j2:j" & lnglastrow).Find(strName(I), LookIn:=xlValues)
If Not c Is Nothing Then
MsgBox "Proxy Candidate Found at " & c.Address
fnd = True
End If
Next I
If Not fnd Then
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
End Sub
Please try the code below:
Sub IDSearch()
'
Dim rg As Range
Dim lnglastrow As Long
Dim intnamemax As Integer
Dim strName() As String
Dim fnd As Boolean
intnamemax = 42
ReDim strName(1 To intnamemax)
strName(1) = "OR123456"
strName(2) = "C00123456"
strName(3) = "UK123456"
lnglastrow = ActiveSheet.UsedRange.Rows.Count
For I = 1 To intnamemax
For J = 2 to lnglastrow
'Set c = Range("j2:j" & lnglastrow).Find(strName(I), LookIn:=xlValues)
If Instr(Range("J" & J).Value, strName(I)) > 0 Then
'If Not c Is Nothing Then
'MsgBox "Proxy Candidate Found at " & c.Address
MsgBox "Proxy Candidate Found at " & "J" & J
fnd = True
'End If
Next J
Next I
If Not fnd Then
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
End Sub
Hope this help
try this
Option Explicit
Sub IDSearch()
Dim intnamemax As Integer
intnamemax = 42
Dim strName() As String
ReDim strName(1 To intnamemax)
strName(1) = "OR123456"
strName(2) = "C00123456"
strName(3) = "UK123456"
Dim lnglastrow As Long
lnglastrow = ActiveSheet.UsedRange.Rows.Count
Dim c As Range
Dim fnd As Boolean
Dim i As Integer
For i = 1 To intnamemax
Set c = Range("j2")
Do While True
If strName(i) = "" Then Exit Do
Set c = c.Resize(lnglastrow).Offset(1).Find(strName(i), LookIn:=xlValues)
If Not c Is Nothing Then
Debug.Print strName(i); " found at " & c.Address
' MsgBox "Proxy Candidate Found at " & c.Address
fnd = True
Else
Exit Do
End If
Loop
Next i
If Not fnd Then
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
End Sub
Check out .FindNext. Something like this (havent tested it).
Dim f As Range
For I = 1 To intnamemax
Set c = Range("j2:j" & lnglastrow).Find(strName(I), LookIn:=xlValues)
If Not c Is Nothing Then
f = c.Address
MsgBox f
Do
Set c = c.FindNext(c)
MsgBox c.Address
Loop While Not c Is Nothing And c.Address <> f
End If
Next I

Put results from Find-function (including extra columns for each result) into array vba

This question is based on a tip I got in the forum some other day, but since this completely changed the problem I'm creating a new post (it seemed a much better solution than the one I proposed but I'm having some issues).
The rationale of my code is to search up and find entries based on ID in column A (from criteria input in txtbox); if the row matches the search criteria then I want the data from column A to J for that entry to be stored in a dynamic array. All the matching entries will be stored there. This array will be used to display all the relevant entries in a listbox in a userform.
The code is the following:
Private Sub cmdFind_Click()
Dim sht As Worksheet
Dim lastrow As Variant
Dim strSearch As String
Dim aCell As Range
Dim row_number As Integer
Dim item_in_review As Variant
Dim y As Integer
Dim Arr() As Variant
y = lstSearch.ListCount
Set sht = ActiveWorkbook.Sheets("a")
lastrow = sht.Range("A" & Rows.Count).End(xlUp).Row
strSearch = txtSearch.Text
Set aCell = sht.Range("A1:A" & lastrow).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
GoTo wfrefvalid
Else
MsgBox "Oops! That Work File does not exist. Please try again.", Title:="Try again"
txtSearch.Value = ""
End If
Exit Sub
wfrefvalid:
row_number = 0
'clears the listbox so that you have dont have a continuously growing list
lstSearch.Clear
Do
DoEvents
row_number = row_number + 1
ReDim Preserve Arr(item_in_review + 1)
item_in_review = sht.Range("A" & row_number)
If item_in_review = txtSearch.Text Then
Arr = item_in_review.Range("A" & row_number & ":J" & row_number)
End If
Loop Until item_in_review = ""
lstSearch.List = Arr
End Sub
The code isn't giving any debugging-errors, however it's also not doing anything when I press the search button. I think the area where I'm struggling is defining the array, and adding each entry to it as the find-function loops through the table (ie the last 12 or so pieces of code).
ANyone have any tips for adding the data from the search (including the extra columns) to the array?
I think the code would to be like this.
Private Sub cmdFind_Click()
Dim sht As Worksheet
Dim lastrow As Variant
Dim strSearch As String
Dim aCell As Range
Dim row_number As Integer
Dim item_in_review As Variant
Dim y As Integer
Dim Arr() As Variant
Dim rngDB As Range
Dim strAddress As String, n As Long
y = lstSearch.ListCount
Set sht = ActiveWorkbook.Sheets("a")
lastrow = sht.Range("A" & Rows.Count).End(xlUp).Row
Set rngDB = sht.Range("a1", "a" & lastrrow)
strSearch = txtSearch.Text
With rngDB
Set aCell = .Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
strAddress = aCell.Address
Do
n = n + 1
ReDim Preserve Arr(1 To 10, 1 To n)
For i = 1 To 10
Arr(i, n) = aCell(1, i)
Next i
Set aCell = .FindNext(aCell)
Loop While strAddress <> aCell.Address
Else
MsgBox "Oops! That Work File does not exist. Please try again.", Title:="Try again"
txtSearch.Value = ""
End If
End With
If n = 1 Then
lstSearch.List = Arr
ElseIf n > 1 Then
lstSearch.List = WorksheetFunction.Transpose(Arr)
End If
End Sub

How to name new worksheets based on values in array and copy associated values from original data set?

I have data in columns P,Q,R. I would like to filter through R, and make a new Worksheet for each unique item in Column R. This new worksheet will also bring along the associated values in P and Q.
Thus far I have learned how to filter the data in R and put the unique values into an array. For each value in the array I made a new sheet named Array1(i) because I am unable to convert the value into a string for some reason. How can I do this in an optimized fashion such that I create a new sheet for each unique value in R and bring along the values in the same rows in P and Q as well? Here is my code:
Also, how do I declare the array dynamically rather than hard coding 50? How can I use a dynamic range for column R?
Note the values in the array will be something like 6X985
Sub testarray()
Dim TestRg As Excel.Range
Dim Array1(50) As Variant
Dim SheetName As String
Dim i, j, k As Integer
i = 1
Set TestRg = Range("R1:R36879")
TestRg.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
For Each c In TestRg.SpecialCells(xlCellTypeVisible)
Array1(i) = c.Value
'SheetName = CStr(c.Value)
Worksheets.Add.Name = i
i = i + 1
Next c
j = i - 1
i = 1
Worksheets("Sheet1").ShowAllData
For Each c In Range("S3:S" & j)
c.Value = Array1(i)
i = i + 1
Next c
k = 1
For Each d In Range("T3:T" & j)
d.Value = k
k = k + 1
Next d
End Sub
The code itself is kind of advanced, I added comments to assist with understanding. I hope it helps:
Sub tgr()
Dim wsData As Worksheet
Dim wsNew As Worksheet
Dim rngData As Range
Dim xlCalc As XlCalculation
Dim arrUnq() As Variant
Dim strSheetName As String
Dim UnqIndex As Long
Dim i As Long
Set wsData = Sheets("Sheet1")
Set rngData = wsData.Range("R1", wsData.Cells(Rows.Count, "R").End(xlUp))
'Disable application items to let code run faster
With Application
xlCalc = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
'Re-enable all the application items just in case there's an error
On Error GoTo CleanExit
'Get the list of unique values from rngData, sorted alphabetically
'Put that list into the arrUnq array
With Sheets.Add
rngData.AdvancedFilter xlFilterCopy, , .Range("A1"), True
.UsedRange.Sort .UsedRange, xlAscending, Header:=xlYes
arrUnq = Application.Transpose(.Range("A2", .Cells(Rows.Count, "A").End(xlUp)).Value)
.Delete
End With
For UnqIndex = LBound(arrUnq) To UBound(arrUnq)
'Verify a valid worksheet name
strSheetName = arrUnq(UnqIndex)
For i = 1 To 7
strSheetName = Replace(strSheetName, Mid(":\/?*[]", i, 1), " ")
Next i
strSheetName = Trim(Left(WorksheetFunction.Trim(strSheetName), 31))
'Check if worksheet name already exists
If Not Evaluate("ISREF('" & strSheetName & "'!A1)") Then
'Sheet doesn't already exist, create sheet
Sheets.Add(After:=Sheets(Sheets.Count)).Name = strSheetName
End If
Set wsNew = Sheets(strSheetName)
wsNew.UsedRange.Clear
'Filter for the unique data
With rngData
.AutoFilter 1, arrUnq(UnqIndex)
'Copy the data from columns P:R to the new sheet
Intersect(wsData.Range("P:R"), .EntireRow).SpecialCells(xlCellTypeVisible).Copy wsNew.Range("A1")
End With
Next UnqIndex
rngData.AutoFilter 'Remove any remaining filters
CleanExit:
With Application
.Calculation = xlCalc
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
If Err.Number <> 0 Then
MsgBox Err.Description, , "Error: " & Err.Number
Err.Clear
End If
End Sub

Resources