为什么我的 Excel 用户表单 VBA 搜索适用于一个 table 列而不是另一个?

Why does my Excel User Form VBA search work with one table column and not another?

我有一个用户表单,它搜索 table 列和 returns 行中的所有值作为表单上的 editable 字段。它太棒了!但我想在搜索中添加另一列。我想使用 11 位数字的最后 4 位数字,因此我创建了另一列,其公式为 returns 最后 4 位数字。

我将变量设置为:

RecordRow = Application.Match(CLng(TextBoxSearch.Value), Range("JobSheet[W/O]"), 0).
它工作正常。该列填充了由此引用填充的 6 位数字:=IFERROR(JobSheetData[@[W/O]],"").

然而,当我把它改成这样时:

RecordRow = Application.Match(CLng(TextBoxSearch.Value), Range("JobSheet[Ticket Search]"), 0) 它不会找到具有搜索值的行。

我在 table 中有一列使用此引用 =IFERROR(JobSheetData[@[ON1Call Ticket '#]],""),然后我有一列 Ticket Search 包含上面提到的最后 4 位数字。

可搜索的 W/O 列的每一行都填充了数据,但 Ticket Search 列的 40% 是空白。我尝试从 W/O 列中删除值以查看是否是问题所在,但它仍然有效。

这是全部代码:

Private Sub CommandButton1_Click()

    Dim RecordRow As Long
    Dim RecordRange As Range
    Dim sChkBoxResult As String
 
    ' Turn off default error handling so Excel does not display
    ' an error if the record number is not found
    On Error Resume Next
        
    'Find the row in the table that the record is in

**This one works:**
     RecordRow = Application.Match(CLng(TextBoxSearch.Value), Range("JobSheet[W/O]"), 0)
        
**This one doesn't:**
     RecordRow = Application.Match(CLng(TextBoxSearch.Value), Range("JobSheet[Ticket Search]"), 0)
            
    ' Set RecordRange to the first cell in the found record
        Set RecordRange = Range("JobSheet").Cells(1, 1).Offset(RecordRow - 1, 0)

    ' If an erro has occured i.e the record number was not found
        If Err.Number <> 0 Then
    
            ErrorLabel.Visible = True
            On Error GoTo 0
            Exit Sub
        
        End If
        
    ' Turn default error handling back on (Let Excel handle errors from now on)
       On Error GoTo 0
    
    ' If the code gets to here the record number was found
    ' Hide the error message 'Not Found'
       ErrorLabel.Visible = False
    
   
    ' and populate the form fields with the record's data
        TextBoxNameAddress.Value = RecordRange(1, 1).Offset(0, 3).Value & " - " & RecordRange(1, 1).Offset(0, 2).Value & " " & RecordRange(1, 1).Value
        TextBoxHold.Value = RecordRange(1, 1).Offset(0, 5).Value
        TextBoxDays.Value = RecordRange(1, 1).Offset(0, 7).Value
        CheckBoxLocate.Value = RecordRange(1, 1).Offset(0, 9).Value
        TextBoxCount.Value = RecordRange(1, 1).Offset(0, 11).Value
        TextBoxFirst.Value = RecordRange(1, 1).Offset(0, 13).Value
        TextBoxOveride.Value = RecordRange(1, 1).Offset(0, 14).Value
        CheckBoxBell.Value = RecordRange(1, 1).Offset(0, 15).Value
        CheckBoxGas.Value = RecordRange(1, 1).Offset(0, 16).Value
        CheckBoxHydro.Value = RecordRange(1, 1).Offset(0, 17).Value
        CheckBoxWater.Value = RecordRange(1, 1).Offset(0, 18).Value
        CheckBoxCable.Value = RecordRange(1, 1).Offset(0, 19).Value
        CheckBoxOther1.Value = RecordRange(1, 1).Offset(0, 20).Value
        CheckBoxOther2.Value = RecordRange(1, 1).Offset(0, 21).Value
        CheckBoxOther3.Value = RecordRange(1, 1).Offset(0, 22).Value
       
End Sub

更新:

下面是一些示例数据的屏幕截图: 数据从 A 列开始

我的最终目标是有一个 if 语句,该语句将 运行 W/O 列上的 6 位数字搜索或 ON1Call Ticket # 列上的 4 位数字搜索基于TextBoxSearch 中字符串的长度 因为它们是 4 位或 6 位,我想我会根据值是否为 >9999 但“ON1Call Ticket #”列是文本列而不是数字,搜索失败。

当第一个实用程序定位到达时,10 或 11 位的票号会自动添加到作业中 Sheet。当电子邮件来自各种公用事业时,票号始终用于识别。我有一个自动化系统,可以提取票号并将传入的位置保存为 PDF 文件,使用票号和一些随机字符作为文件名。我将其设置为像这样拆分文件名:123456 7890 - jkes.pdf。一个人现在重命名该文件以指示该文件中包含哪些实用程序,并使用用户表单中的中间一组 4 个数字: 找到正确的记录并选中相应实用程序的复选框。我不希望用户必须输入所有 11 位数字,我试图避免使用辅助列,但我无法弄清楚如何让 4 位数字搜索只查看票号的最后 4 位数字。

其他时候我们需要通过工单号来查找,它是6位数字。

我可能会这样做:

Private Sub CommandButton1_Click()

    Dim RecordRow As Variant '<<< not Long, or throws an error when no match
    Dim vSearch As Long, col, lo As ListObject
    
    Set lo = ThisWorkbook.Worksheets("Data").ListObjects("JobSheet") 'adjust sheet name
    vSearch = CLng(TextBoxSearch.Value)
    
    For Each col In Array("W/O", "Ticket Search") 'loop over columns to search in
        'no need for On Error Resume Next - test the return value from Match instead
        RecordRow = Application.Match(vSearch, lo.ListColumns(col).DataBodyRange, 0)
        If Not IsError(RecordRow) Then Exit For 'got a hit - stop searching
    Next col
    
    ErrorLabel.Visible = IsError(RecordRow) 'hide/show error label
    If Not IsError(RecordRow) Then LoadRecord lo.ListRows(RecordRow).Range
    
End Sub

编辑:澄清后 - 不同的搜索方法取决于输入的长度

Private Sub CommandButton1_Click()

    Dim RecordRow As Variant '<<< not Long, or throws an error when no match
    Dim vSearch, col, lo As ListObject
    
    Set lo = ThisWorkbook.Worksheets("Data").ListObjects("JobSheet") 'adjust sheet name
    
    vSearch = TextBoxSearch.Value
    If Not IsNumeric(vSearch) Then
        MsgBox "Search value must be numeric!"
    End If
    'decide how to search based on length of search input
    Select Case Len(vSearch)
        Case 4
            'call custom function instead of Match
            RecordRow = EndsWithMatch(vSearch, lo.ListColumns("ON1Call Ticket #").DataBodyRange)
        Case 6
            'cast search value to Long before using Match
            RecordRow = Application.Match(CLng(vSearch), lo.ListColumns("W/O").DataBodyRange, 0)
        Case Else
            MsgBox "Search value must either 4 or 6 digits!"
    End Select
   
    ErrorLabel.Visible = IsError(RecordRow) 'hide/show error label
    If Not IsError(RecordRow) Then LoadRecord lo.ListRows(RecordRow).Range
    
End Sub
'search a single-column range of data for an "ends with" match to `vSearch`
Function EndsWithMatch(vSearch, rngSrch As Range)
    Dim i As Long, arr
    arr = rngSrch.Value
    For i = 1 To UBound(arr, 1)
        If arr(i, 1) Like "*" & vSearch Then
            EndsWithMatch = i
            Exit Function 'done searching
        End If
    Next i
    EndsWithMatch = CVErr(xlErrNA) 'no match: return error value as in Match()
End Function

两个答案的共同点(编辑 - 添加了一些保存编辑记录的建议):

Dim editedRow as Range 'holds a reference to the row loaded for editing

'Better as a stand-alone method which you can call from other places...
Sub LoadRecord(sourceRow As Range)
    With sourceRow
        TextBoxNameAddress.Value = .Cells(4).Value & " - " & _
                        .Cells(3).Value & " - " & .Cells(1).Value
        TextBoxHold.Value = .Cells(6).Value
        'etc for other fields
    End With
    Set editedRow = sourceRow 'set a global for the row being edited
    'also enable the "Save" button... 
End Sub

Sub SaveRecord()
    If Not editedRow Is Nothing Then
        With editedRow
            .Cells(6).Value = TextBoxHold.Value
            'etc for the other fields
        End With
    Else
        MsgBox "No row is being edited!"
    End If
End Sub

easier/safer 测试 Match() 中的 return 值而不是关闭错误。