Help with a VBA Search function across multiple sheets to return a match

UMAKEMESIK

Active Member
Joined
Oct 3, 2005
Messages
378
TO ALL,

I have a workbook with multiple sheets.
The top level sheet is where I enter information to
Look for matching data on the following sheets.

I use Vlookup for an exact match when I know the part number and it works great.

I would like to add a search function for when I don’t know the part number
And am looking for a match of Length Width and depth –

The returned result would be:
Part number – Length – widty and depth.

I would also like to add a variance of + 1 and -1
So the result would find all units with the exact match and all those over and under by 1”

I would like this to run when the user enters a number and presses ENTER. ( or a click of a button would be ok to run the command)

So the user would enter 12 – 3 – 10 in three different cells all on the same line – Press Enter
And the result would show up possibly on the same line
But then all of the units over and under could show up right below.

I am pretty sure I will need VB for this as I think this goes beyond what Vlookup can accomplish.

I can explain more if needed.

Thanks in advance.
 

Excel Facts

Do you hate GETPIVOTDATA?
Prevent GETPIVOTDATA. Select inside a PivotTable. In the Analyze tab of the ribbon, open the dropown next to Options and turn it off
Hi Martin,

If you provide an example workbook that shows the layout of your data, that shouldn't be too difficult to code. Without an example, we would need a lot of Q&A to get the specifics.

Could you upload a copy of an example workbook to a sharing site and provide a link. Alternatively you could send me a PM and we'll exchange email addresses.
 
Upvote 0
Martin, Thanks for sending your file.

Here's some code you can try. I'd suggest using a button to execute the search.

Code:
Sub FindData()
'--searches multiple data sheets to find records
'    that are exact match to user input parameters or
'    near matches that are within specified variance.

 Dim adParams() As Double, adThisRecord() As Double
 Dim lNdx As Long, lRow As Long, lCol As Long
 Dim lMatchResultCount As Long, lNearResultCount As Long
 Dim lTotalResultCount As Long
 Dim rParams As Range, rSaveActiveCell As Range
 Dim vData As Variant, vMatchResults As Variant, vNearResults As Variant
 Dim wksData As Worksheet, wksResults As Worksheet

 '--maximum variance to be considered near match
 Const dVARIANCE As Double = 1
 
 '--number of search parameters (length, width, depth)
 Const lPARAM_COUNT As Long = 3
 
 '--number of fields to be read for matching records
 '  1=StockNbr; 2=DesignNbr; 3=Length; 4=Width; 5=Depth; 6=Flute
 Const lRESULT_FIELDS_COUNT As Long = 6
 
 '--column nbr of length field in data sheets
 Const lFIRST_PARAM_COL As Long = 3
 
 '--limit of matches to be returned
 Const lMAX_RESULTS As Long = 1000
 
 '--location of range with search parameters
 Set wksResults = Sheets("Stock box Lookup")
 Set rParams = wksResults.Range("H4").Resize(1, lPARAM_COUNT)
 
 '--clear previous search results
 With wksResults
   .Rows("5:" & Rows.Count).ClearContents
   .Range("F4:G4,K4").ClearContents
 End With
 Set rSaveActiveCell = ActiveCell
 
'--read and validate search parameters
 If Application.CountA(rParams) = lPARAM_COUNT And _
   Application.Count(rParams) = lPARAM_COUNT Then
   '--write params to array that used to compare to records
   ReDim adParams(1 To lPARAM_COUNT)
   For lNdx = 1 To lPARAM_COUNT
      adParams(lNdx) = rParams(1, lNdx)
   Next lNdx
   
 Else
   MsgBox "Enter numeric values for Length, Width and Depth"
   GoTo ExitProc
 End If
 
 '--size arrays that will hold records meeting criteria
 ReDim vMatchResults(1 To lMAX_RESULTS, 1 To lRESULT_FIELDS_COUNT)
 ReDim vNearResults(1 To lMAX_RESULTS, 1 To lRESULT_FIELDS_COUNT)
 
 ReDim adThisRecord(1 To lPARAM_COUNT)
 
 '--step through each data worksheet and find records that are matches
 '    or near matches to parameters
 
 For Each wksData In ActiveWorkbook.Worksheets(Array( _
   "Sheet2", "Sheet3", "Sheet4", "Sheet5", "Sheet6", "Sheet7"))
   
   vData = wksData.Range("A1").CurrentRegion.Value
   
   For lRow = 1 To UBound(vData, 1)
     '--read each record's values to be compared vs parameters
      For lNdx = 1 To lPARAM_COUNT
         On Error Resume Next
         adThisRecord(lNdx) = vData(lRow, lFIRST_PARAM_COL + lNdx - 1)
         If Err.Number <> 0 Then
            Err.Clear
            MsgBox "Non-numeric data found in numeric field: " & vbCr _
               & "Sheet: " & wksData.Name & vbCr _
               & "Row: " & lRow
            Resume Next
         End If
         On Error GoTo 0
      Next lNdx

      If bIsMatch(dArr1:=adThisRecord, dArr2:=adParams) Then
        '--write exact match to next record
         lMatchResultCount = lMatchResultCount + 1
         If lMatchResultCount > lMAX_RESULTS Then
            MsgBox "Matches found exceed maximum allowed"
            GoTo ExitProc
         End If
         For lCol = 1 To lRESULT_FIELDS_COUNT
            vMatchResults(lMatchResultCount, lCol) = vData(lRow, lCol)
         Next lCol
                  
      ElseIf bIsNearMatch(dArr1:=adThisRecord, dArr2:=adParams, _
         dMaxVariance:=dVARIANCE) Then
        '--write near match to next record
         lNearResultCount = lNearResultCount + 1
         If lNearResultCount > lMAX_RESULTS Then
            MsgBox "Near matches found exceed maximum allowed"
            GoTo ExitProc
         End If
         For lCol = 1 To lRESULT_FIELDS_COUNT
            vNearResults(lNearResultCount, lCol) = vData(lRow, lCol)
         Next lCol
     End If
     
   Next lRow
 Next wksData

 '--write results
 If lMatchResultCount Then
   wksResults.Range("F4").Resize(lMatchResultCount, lRESULT_FIELDS_COUNT) = vMatchResults
 Else
   MsgBox "No exact match meeting search parameters found"
 End If

 If lNearResultCount Then
   wksResults.Range("F4").Offset(IIf(lMatchResultCount, lMatchResultCount, 1)) _
      .Resize(lNearResultCount, lRESULT_FIELDS_COUNT) = vNearResults
 End If
 
 lTotalResultCount = lMatchResultCount + lNearResultCount
 If lTotalResultCount > 1 Then
   '--copy down formulas for result rows
   With wksResults.Range("A4:E4")
      .Copy
      .Resize(lTotalResultCount).PasteSpecial (xlPasteFormulas)
   End With
 End If
  
 rSaveActiveCell.Select
 
ExitProc:
 Application.CutCopyMode = False
End Sub

Private Function bIsMatch(ByRef dArr1() As Double, _
   ByRef dArr2() As Double) As Boolean
'--compares corresponding elements of each array.
'  returns True if all are equal, otherwise False.
'--assumes arrays have already been validated as vectors
'  with same lbound and size

 Dim bReturn As Boolean
 Dim lNdx As Long
 
 '--return true unless pair of non-matching elements found
 bReturn = True
 
 For lNdx = LBound(dArr1) To UBound(dArr1)
      If dArr1(lNdx) <> dArr2(lNdx) Then
         bReturn = False
         Exit For
      End If
 Next lNdx
 
 bIsMatch = bReturn
End Function

Private Function bIsNearMatch(ByRef dArr1() As Double, _
   ByRef dArr2() As Double, ByVal dMaxVariance As Double) As Boolean
'--compares corresponding elements of each array.
'  returns True if none have more than the specified variance, otherwise False.
'--assumes arrays have already been validated as vectors
'  with same lbound and size

 Dim bReturn As Boolean
 Dim lNdx As Long
 
 '--return true unless pair of non-matching elements found
 bReturn = True
 
 For lNdx = LBound(dArr1) To UBound(dArr1)
      If Abs(dArr1(lNdx) - dArr2(lNdx)) > dMaxVariance Then
         bReturn = False
         Exit For
      End If
 Next lNdx
 
 bIsNearMatch = bReturn
End Function
 
Last edited:
Upvote 0
Martin, Thanks for sending your file.

Here's some code you can try. I'd suggest using a button to execute the search.

Code:
Sub FindData()
'--searches multiple data sheets to find records
'    that are exact match to user input parameters or
'    near matches that are within specified variance.

 Dim adParams() As Double, adThisRecord() As Double
 Dim lNdx As Long, lRow As Long, lCol As Long
 Dim lMatchResultCount As Long, lNearResultCount As Long
 Dim lTotalResultCount As Long
 Dim rParams As Range, rSaveActiveCell As Range
 Dim vData As Variant, vMatchResults As Variant, vNearResults As Variant
 Dim wksData As Worksheet, wksResults As Worksheet

 '--maximum variance to be considered near match
 Const dVARIANCE As Double = 1
 
 '--number of search parameters (length, width, depth)
 Const lPARAM_COUNT As Long = 3
 
 '--number of fields to be read for matching records
 '  1=StockNbr; 2=DesignNbr; 3=Length; 4=Width; 5=Depth; 6=Flute
 Const lRESULT_FIELDS_COUNT As Long = 6
 
 '--column nbr of length field in data sheets
 Const lFIRST_PARAM_COL As Long = 3
 
 '--limit of matches to be returned
 Const lMAX_RESULTS As Long = 1000
 
 '--location of range with search parameters
 Set wksResults = Sheets("Stock box Lookup")
 Set rParams = wksResults.Range("H4").Resize(1, lPARAM_COUNT)
 
 '--clear previous search results
 With wksResults
   .Rows("5:" & Rows.Count).ClearContents
   .Range("F4:G4,K4").ClearContents
 End With
 Set rSaveActiveCell = ActiveCell
 
'--read and validate search parameters
 If Application.CountA(rParams) = lPARAM_COUNT And _
   Application.Count(rParams) = lPARAM_COUNT Then
   '--write params to array that used to compare to records
   ReDim adParams(1 To lPARAM_COUNT)
   For lNdx = 1 To lPARAM_COUNT
      adParams(lNdx) = rParams(1, lNdx)
   Next lNdx
   
 Else
   MsgBox "Enter numeric values for Length, Width and Depth"
   GoTo ExitProc
 End If
 
 '--size arrays that will hold records meeting criteria
 ReDim vMatchResults(1 To lMAX_RESULTS, 1 To lRESULT_FIELDS_COUNT)
 ReDim vNearResults(1 To lMAX_RESULTS, 1 To lRESULT_FIELDS_COUNT)
 
 ReDim adThisRecord(1 To lPARAM_COUNT)
 
 '--step through each data worksheet and find records that are matches
 '    or near matches to parameters
 
 For Each wksData In ActiveWorkbook.Worksheets(Array( _
   "Sheet2", "Sheet3", "Sheet4", "Sheet5", "Sheet6", "Sheet7"))
   
   vData = wksData.Range("A1").CurrentRegion.Value
   
   For lRow = 1 To UBound(vData, 1)
     '--read each record's values to be compared vs parameters
      For lNdx = 1 To lPARAM_COUNT
         On Error Resume Next
         adThisRecord(lNdx) = vData(lRow, lFIRST_PARAM_COL + lNdx - 1)
         If Err.Number <> 0 Then
            Err.Clear
            MsgBox "Non-numeric data found in numeric field: " & vbCr _
               & "Sheet: " & wksData.Name & vbCr _
               & "Row: " & lRow
            Resume Next
         End If
         On Error GoTo 0
      Next lNdx

      If bIsMatch(dArr1:=adThisRecord, dArr2:=adParams) Then
        '--write exact match to next record
         lMatchResultCount = lMatchResultCount + 1
         If lMatchResultCount > lMAX_RESULTS Then
            MsgBox "Matches found exceed maximum allowed"
            GoTo ExitProc
         End If
         For lCol = 1 To lRESULT_FIELDS_COUNT
            vMatchResults(lMatchResultCount, lCol) = vData(lRow, lCol)
         Next lCol
                  
      ElseIf bIsNearMatch(dArr1:=adThisRecord, dArr2:=adParams, _
         dMaxVariance:=dVARIANCE) Then
        '--write near match to next record
         lNearResultCount = lNearResultCount + 1
         If lNearResultCount > lMAX_RESULTS Then
            MsgBox "Near matches found exceed maximum allowed"
            GoTo ExitProc
         End If
         For lCol = 1 To lRESULT_FIELDS_COUNT
            vNearResults(lNearResultCount, lCol) = vData(lRow, lCol)
         Next lCol
     End If
     
   Next lRow
 Next wksData

 '--write results
 If lMatchResultCount Then
   wksResults.Range("F4").Resize(lMatchResultCount, lRESULT_FIELDS_COUNT) = vMatchResults
 Else
   MsgBox "No exact match meeting search parameters found"
 End If

 If lNearResultCount Then
   wksResults.Range("F4").Offset(IIf(lMatchResultCount, lMatchResultCount, 1)) _
      .Resize(lNearResultCount, lRESULT_FIELDS_COUNT) = vNearResults
 End If
 
 lTotalResultCount = lMatchResultCount + lNearResultCount
 If lTotalResultCount > 1 Then
   '--copy down formulas for result rows
   With wksResults.Range("A4:E4")
      .Copy
      .Resize(lTotalResultCount).PasteSpecial (xlPasteFormulas)
   End With
 End If
  
 rSaveActiveCell.Select
 
ExitProc:
 Application.CutCopyMode = False
End Sub

Private Function bIsMatch(ByRef dArr1() As Double, _
   ByRef dArr2() As Double) As Boolean
'--compares corresponding elements of each array.
'  returns True if all are equal, otherwise False.
'--assumes arrays have already been validated as vectors
'  with same lbound and size

 Dim bReturn As Boolean
 Dim lNdx As Long
 
 '--return true unless pair of non-matching elements found
 bReturn = True
 
 For lNdx = LBound(dArr1) To UBound(dArr1)
      If dArr1(lNdx) <> dArr2(lNdx) Then
         bReturn = False
         Exit For
      End If
 Next lNdx
 
 bIsMatch = bReturn
End Function

Private Function bIsNearMatch(ByRef dArr1() As Double, _
   ByRef dArr2() As Double, ByVal dMaxVariance As Double) As Boolean
'--compares corresponding elements of each array.
'  returns True if none have more than the specified variance, otherwise False.
'--assumes arrays have already been validated as vectors
'  with same lbound and size

 Dim bReturn As Boolean
 Dim lNdx As Long
 
 '--return true unless pair of non-matching elements found
 bReturn = True
 
 For lNdx = LBound(dArr1) To UBound(dArr1)
      If Abs(dArr1(lNdx) - dArr2(lNdx)) > dMaxVariance Then
         bReturn = False
         Exit For
      End If
 Next lNdx
 
 bIsNearMatch = bReturn
End Function


jERRY,

Much Much Thanks!!
Works exactly as described.

Now I want to build the sheet and incorporate with my
existing stock box look up.

in the top part of the sheet I will have the ability to look up a stock box by its name.

in the lower part I will have the search function.

I wanted to move some of the fields but can't find exactly where that is executed in the code.
I tried changing some variables in the code with no success.

the input fields are on row 4.

wanted to move down to row 7 for example
and all the results would follow below.

also, When an exact match is entered the match is placed on the entry row.

I would like to keep the entry row as only an entry row and I will label as such
and all results - including exact matches would follow below.

any help would be appreciated.

thanks
 
Upvote 0
Hi Martin,

If you provide an example workbook that shows the layout of your data, that shouldn't be too difficult to code. Without an example, we would need a lot of Q&A to get the specifics.

Could you upload a copy of an example workbook to a sharing site and provide a link. Alternatively you could send me a PM and we'll exchange email addresses.

---------------------------

Found this to work:

Code:
'--write results
 If lMatchResultCount Then
   wksResults.Range("F12").Resize(lMatchResultCount, lRESULT_FIELDS_COUNT) = vMatchResults
 Else
   MsgBox "No exact match meeting search parameters found"
 End If

 If lNearResultCount Then
   wksResults.Range("F12").Offset(IIf(lMatchResultCount, lMatchResultCount, 1)) _
      .Resize(lNearResultCount, lRESULT_FIELDS_COUNT) = vNearResults
 End If
 
 lTotalResultCount = lMatchResultCount + lNearResultCount
 If lTotalResultCount > 1 Then

This changes the placement of the results.
still looking how to change the input.

thanks
 
Upvote 0
To move the input range down to row 7, modify this part...

Code:
 '--location of range with search parameters
 Set wksResults = Sheets("Stock box Lookup")
 Set rParams = wksResults.Range("H7").Resize(1, lPARAM_COUNT)
 
 '--clear previous search results
 With wksResults
   .Rows("12:" & Rows.Count).ClearContents
 End With

One way to make your code more adaptable to these kinds of changes in layout would be to use a Named Range for your 3 Input Cells.
The code can reference the named range, and it will find the input cells if you move that range.
 
Upvote 0
To move the input range down to row 7, modify this part...

Code:
 '--location of range with search parameters
 Set wksResults = Sheets("Stock box Lookup")
 Set rParams = wksResults.Range("H7").Resize(1, lPARAM_COUNT)
 
 '--clear previous search results
 With wksResults
   .Rows("12:" & Rows.Count).ClearContents
 End With

One way to make your code more adaptable to these kinds of changes in layout would be to use a Named Range for your 3 Input Cells.
The code can reference the named range, and it will find the input cells if you move that range.


Thanks for the quick response:

Here is where I am at, I am a designer, and have built many forms over the years with the gracious help of users from Mr. Excel. I have learned how to manipulate some code and a lot of cut a pasting but nothing like this. Any and all help is much appreciated.

I am almost there with the formatting.

I have moved some things over.

Code:
'--location of range with search parameters
 Set wksResults = Sheets("Stock box Lookup")
 Set rParams = wksResults.Range("C7").Resize(1, lPARAM_COUNT)
 
 '--clear previous search results
 With wksResults
   .Rows("8:" & Rows.Count).ClearContents
   .Range("f8:G8,K8").ClearContents
 End With
 Set rSaveActiveCell = ActiveCell

and

Code:
'--WRITE RESULTS
 '------------------------------------------------------------------------------
 '---the exact match will be placed on f12 and below
 '----if no exact match is found the results will be placed on f13 and below
 '------------------------------------------------------------------------------
 
 If lMatchResultCount Then
   wksResults.Range("C8").Resize(lMatchResultCount, lRESULT_FIELDS_COUNT) = vMatchResults
 Else
   MsgBox "No exact match meeting search parameters found"
 End If

 If lNearResultCount Then
   wksResults.Range("C8").Offset(IIf(lMatchResultCount, lMatchResultCount, 1)) _
      .Resize(lNearResultCount, lRESULT_FIELDS_COUNT) = vNearResults
 End If

but now I am having some "Clear Contents" issues.
my input fields are c7, d7 and e7

an exact match will be placed on c8 through h8 and below if multiple matches

a close match will be placed on c9 through h9 and below if multiple results

cells c, d and e are being cleared

it appears to be random on how many of those rows are being cleared
but I am sure it is not.

so my input results will be cleared after hitting the button
and columns c,d and e
leaving the depth of the box (g)
the width of the box (f)
and the flute (h)

thanks
 
Upvote 0
One clarification before getting to the ClearContents item...

In the example file you provided, some of the box sizes in the data sheets matched in all 3 dimensions.

That's why the code I suggested allowed for a variable number of exact matches and a variable number of near matches.
I assumed you would want to show all the exact matches above all the near matches.

What do you want to do if more than 1 exact match is found?
 
Upvote 0
One clarification before getting to the ClearContents item...

In the example file you provided, some of the box sizes in the data sheets matched in all 3 dimensions.

That's why the code I suggested allowed for a variable number of exact matches and a variable number of near matches.
I assumed you would want to show all the exact matches above all the near matches.

What do you want to do if more than 1 exact match is found?

---------------------------------------------------------------------------------------------------------------------------------------------------


I Have a few more items to enter on the data sheets and there may be a match of the three variables length, width and depth on different sheets.
in these cases I would like the results to return both.

I had another look at the sheet and trying to keep it simple.

Hopefully this can be completed with a clean swap of some column letters.

Here is the redesign -

---------------------------------------------------------------------------------------------------------------------

I will take care of the top section with a vlookup.

for the search we are working on this would happen in the bottom section;
see below.

-------------------------------------------------------------------------------------------------------------------

I would like the user to enter a Length, width and depth number

in b10, c10, d10

Then click on the button. ( the one you provided)

the results would be returned:

stock box number (from column A) in the data sheets
return this result in column A

design number ( from column B) in the data sheets
return this value to column C

Length ( from column c) in the data sheets
return this value to column D

Width ( from column D) in the data sheets
return this value to column E

Depth ( from column E) in the data sheets
Return this value to Column F

Flute ( from Column F) in the data sheets
Return this value to Column G


If more than one result then they will all follow below as already accomplished.

Hope this makes it simple.

thanks
 
Upvote 0

Forum statistics

Threads
1,223,761
Messages
6,174,347
Members
452,556
Latest member
Chrisolowolafe

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top