Home > Back-end >  Find Function to Find If Cell Contains a Partial Match if Applicable
Find Function to Find If Cell Contains a Partial Match if Applicable

Time:11-17

I am looking for a function that takes two input arguments, boardtype and subsysnum and then finds the row index that has that specific combination. However, if subsysnum column is blank then continue on. Only some cases will have a subsysnum value. boardtype will have to be an exact match. For the purpose of the function, I have written so far, boardtype and subsysnum are defined both as strings above. column defined when calling the function will be either 3 or 5

I have so far called the worksheet that has the lookup table in it and believe I have found the row index for the boardtype now I just need to incorporate if subsysnum value can be found in the second column then find the row combination index, else continue with the blank second column to find the lookup value. This is what my data looks like

enter image description here

Using the table above say for example my boardtype = AX-6 and my subsysnum = WD1234TEST I want the macro to get the row index of 9 since subsysnum = WD1234 is contained in the subsysnum number WD1234TEST. If subsysnum = WD298588 trial, then the row index return should be 8 since it is contained in the value. Finally, if subsysnum value cannot be found in column 2, then it should return a row index of 7 for AX-6 with the blank cell next to it.

This is what I have tried so far, however, I am not getting any value for GetClock

Function GetClock(boardtype As String, subsysnum As String, column As Long, Optional partialFirst As Boolean = False) As Variant  
    Dim wbSrc As Workbook, ws As Worksheet, r1 As Range, r2 As Range, board_range As Range, firstAddress As String
    FunctionName = "GetClock"
    Set wbSrc = Workbooks.Open("C:\Documents\LookupTable.xlsx")
    Set ws = wbSrc.Worksheets("Clock")

    Set r1 = ws.Columns(1)
    Set r2 = ws.Columns(2)

With r1
        Set board_range = r1.Find(What:=boardtype, LookAt:=xlWhole, LookIn:=xlFormulas, MatchCase:=True) ' find board type row
            If Not board_range Is Nothing Then
                firstAddress = board_range.Address ' save board type address
            Else
                    ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", "") & SectionName & ": " & "Board " & boardtype & " could not be found in lookup table" & vbNewLine
                Exit Function
            End If
        Do While Not board_range Is Nothing 
            Set subsysnum_range = r2.Find(What:=subsysnum, LookIn:=xlFormulas, LookAt:=IIf(partialFirst, xlPart, xlWhole), MatchCase:=True)
                    GetClock = ws.cells(board_range.row, column).value
            Exit Function 

        Set board_range = r1.Find(boardtype, board_range)
            If board_range.Address = firstAddress Then
                GetClock = ws.cells(Range(firstAddress).row, column).value 
                If GetClock = 0 Then
                    ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", "") & SectionName & ": " & "lookup table missing value" & vbNewLine
                End If
                Exit Function
            End If
     Loop
End With
End Function

enter image description here

UPDATE: Where Column(13) represents the column in the Data Sheet that has the subsysnum stored

Function GetClock(boardtype As String, subsysnum As String, column As Long, Optional partialFirst As Boolean = False) As Double  
Dim wbSrc As Workbook, ws As Worksheet, r1 As Range, r2 As Range, board_range As Range, firstAddress As String, subsysnum_range As Range, rng_board As Range, rng_subsys As Range
FunctionName = "GetExternalClock"
Set wbSrc = Workbooks.Open("C:\Documents\LookupTable.xlsx")
Set ws = wbSrc.Worksheets("Clock")

Dim wb As Workbook, dataws As Worksheet
Set wb = Workbooks("S93.xlsm")
Set dataws = wb.Worksheets("Data Sheet")
Set r1 = ws.Columns(1)
Set r2 = ws.Columns(2)

With r1
    Set board_range = r1.Find(What:=boardtype, LookAt:=xlWhole, LookIn:=xlFormulas, MatchCase:=True) ' find board type row
        If Not board_range Is Nothing Then
            firstAddress = board_range.Address ' save board type address
        Else
                ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", "") & SectionName & ": " & "Board " & boardtype & " could not be found in lookup table" & vbNewLine
            Exit Function
        End If
Dim subsys As Range, cell As String
    Do While Not board_range Is Nothing ' while board type is not nothing look for value of cell in column 2
        For Each subsys In Range("B3:B12")
            cell = subsys.value
            Set subsys_rng = dataws.Columns(13).Find(What:=cell, LookIn:=xlFormulas, LookAt:=IIf(partialFirst, xlPart, xlWhole), MatchCase:=True)
            If cell = "" Then
            GoTo Skip
            Else
                GetClock= ws.cells(subsys_rng.row, column).value
            End If
 
 Skip:
    Next subsys
    Exit Function

     'if intersect.value does not equal sysnum, then it will set board_range below only after it has checked every matching cell in column 1
    Set board_range = r1.Find(boardtype, board_range)
        If board_range.Address = firstAddress Then
            GetClock= ws.cells(Range(firstAddress).row, column).value ' boardtype row index with empty cell in r2
            If GetClock= 0 Then
                ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", "") & SectionName & ": " & "lookup table missing value" & vbNewLine
            End If
            Exit Function
        End If
    Loop
End With
Exit Function
End Function

CodePudding user response:

Please, check the next function:

Function GetClock(wbSrc As Workbook, boardtype As String, subsysnum As String, Optional column As Long = 0) As Long
   Dim ws As Worksheet, lastR As Long, arr, i As Long, dict As Object
   
    Set ws =  wbSrc.Worksheets("Clock")
    lastR = ws.Range("A" & ws.rows.count).End(xlUp).row
    
    arr = ws.Range("A2:F" & lastR).Value2
    
    Set dict = CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(arr)
        If arr(i, 1) = boardtype And InStr(arr(i, 2), subsysnum) > 0 Then
             If column = 0 Then
                dict(1) = i   1
             Else
                dict(1) = arr(i, column)
             End If
        ElseIf arr(i, 1) = boardtype Then
           If column = 0 Then
                dict(2) = i   1
             Else
                dict(2) = arr(i, column)
             End If
        End If
    Next i
    If dict.Exists(1) Then
        GetClock = dict(1)
    ElseIf dict.Exists(2) Then
       GetClock = dict(2)
    End If
End Function

It can be tested being called as:

Sub testGetClock()
   Dim wbSrc As Workbook
   On Error Resume Next
     Set wbSrc = Workbooks("LookupTable.xlsx")
    On Error GoTo 0
    If wbSrc Is Nothing Then Set wbSrc = Workbooks.Open("C:\Documents\LookupTable.xlsx")
    
   Debug.Print GetClock("AX-6", "WD298588")
   Debug.Print GetClock("AX-6", "WD1234")
   Debug.Print GetClock("AX-6", "WD1234", 3)
End Sub

If you use the column parameter and the returned value may be a string the function return have to be changed from Long to Variant...

Now, in case of no match it returns zero (0).

Please, send some feedback after testing it

CodePudding user response:

A simple loop over an array would be easier to manage, along with caching the lookup table between calls:

Function GetClock(boardtype As String, subsysnum As String, column As Long, _
                  Optional partialSubSys As Boolean = False) As Variant
    
    Static data As Variant
    Dim r As Long, rNoSub As Long, rMatchSub As Long, rMatch As Long, wldCard As String
    
    If IsEmpty(data) Then 'data not already cached?
        With Workbooks.Open("C:\Documents\LookupTable.xlsx")
            data = .Worksheets("Clock").Range("A1").CurrentRegion.Value
            .Close False
        End With
    End If
    
    wldCard = IIf(partialSubSys, "*", "") 'using a wildcard?
    For r = 2 To UBound(data, 1)
        If data(r, 1) = boardtype Then
            If Len(data(r, 2)) = 0 And rNoSub = 0 Then
                rNoSub = r       'first matched line with no subsystem listed
            ElseIf subsysnum Like data(r, 2) & wldCard Then  '<<FIXED
                rMatchSub = r    'subsystem matched
                Exit For         'stop checking
            End If
       End If
    Next r
    
    rMatch = IIf(rMatchSub > 0, rMatchSub, rNoSub) 'prefer two-part match...
    If rMatch > 0 Then 'any match (one- or two-part) ?
        GetClock = data(rMatch, column)
    Else
        GetClock = CVErr(xlErrNA)
        'populate error message as needed
    End If
End Function
  • Related