是否可以代替Vlookup查找大型20k行表?

时间:2017-08-01 21:11:30

标签: excel excel-vba vba

我正在开发一个由一系列表单和几个宏组成的大型项目。我需要逐月更新的主要报告是21K行并且还在增长。它在12个单独的列中收集所有12个月的更新。要完成"更新",我必须匹配列#34; A"中包含的主文件中的部件号(21k行是所有部件号及其信息),并将其与另一个匹配由部件号生成的报告(此时间包含在列#34; B"中)如果匹配(需要与之匹配),请返回以下内容:

将第9列sht1的值放入由变量

指定的sht列

将第7列sht1的值放在sht第27列

将第11列的值sht 1置于第34列

每次匹配时,逐行循环,直到列A中包含的最后一个部件号为止。

以下代码有效,但我想知道我应该写一个更好的方法吗?这是处理速度和准确性的最佳选择吗?我刚刚在另一个代码块中意识到,同样的方法没有执行完全匹配,现在已经抛出一个红旗,让我可能改变我的方法。我绝对需要这个准确,它必须完全匹配,或将内容留空。

'Set variable with cell range value for ABC Code based on month selected by User

Dim ABCCodeCell As Integer
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim sht1 As Worksheet
Dim sht As Worksheet
Dim lRow As Long
Dim rng As Range

Set wb1 = Workbooks(vFileName1) 'ABC Matrix File
Set wb2 = Workbooks(vFileName2) 'Cycle Count Remainder Browse File
Set sht = wb1.Worksheets(1) 'ABC Matrix File
Set sht1 = wb2.Worksheets(1) 'Cycle Count Remainder Browse File

lRow = sht.Cells(sht.Rows.Count, 1).End(xlUp).Row

Select Case ABCMatrixMonthSelect.ComboBox1.value
    Case "January": ABCCodeCell = 21
    Case "February": ABCCodeCell = 23
    Case "March": ABCCodeCell = 25
    Case "April": ABCCodeCell = 3
    Case "May": ABCCodeCell = 5
    Case "June": ABCCodeCell = 7
    Case "July": ABCCodeCell = 9
    Case "August": ABCCodeCell = 11
    Case "September": ABCCodeCell = 13
    Case "October": ABCCodeCell = 15
    Case "November": ABCCodeCell = 17
    Case "December": ABCCodeCell = 19
End Select

'Execute Find (Vlookup)


On Error Resume Next
For i = 2 To lRow
If sht.Cells(i, 1).value <> "" Then
    Set rng = sht1.Range("B:B").Find(sht.Cells(i, 1).value)
    If Not rng Is Nothing Then
         sht.Cells(i, ABCCodeCell).value = sht1.Cells(rng.Row, 9).value
         sht.Cells(i, 27).value = sht1.Cells(rng.Row, 7).value
         sht.Cells(i, 34).value = sht1.Cells(rng.Row, 11).value
    End If
End If
Next

3 个答案:

答案 0 :(得分:1)

我不会评论您的代码是否是速度等最佳代码,因为Stack Overflow并不是真正的主题 - 这些问题应该在{{3 }}

然而,我会回答你的问题(需要完全匹配)&#34;注释:

Excel允许用户在执行查找时指定各种选项:

Code Review

默认情况下,大多数(全部?)这些选项会被记住并在下一个查找中使用,可以是用户执行的手动查找,也可以是VBA代码中编程的Find

您当前的查找(sht1.Range("B:B").Find(sht.Cells(i, 1).value))未指定What参数以外的任何参数,因此将使用上次用户使用的LookIn {{1}的值}和LookAt参数。

如果您想要执行完全匹配,并且您不相信用户在运行代码之前没有完成部分匹配,则应明确说明您希望使用哪些选项。

我建议您将MatchCase更改为:

Find

答案 1 :(得分:1)

与使用Find()相比,在大型循环中运行Match()非常慢。

例如,在20,000个不同值的列中查找2000个值:

Sub Tester()

    Dim i As Long, f As Range, t, m, n As Long

    t = Timer
    For i = 1 To 2000
        Set f = Columns(1).Find(what:="Prod_" & Format(i, "000000"), _
                                lookat:=xlWhole, LookIn:=xlValues)
        If Not f Is Nothing Then
            n = n + 1
        End If
    Next i
    Debug.Print "Find", Timer - t, "found " & n

    t = Timer
    n = 0
    For i = 1 To 2000
        m = Application.Match("Prod_" & Format(i, "000000"), Columns(1), 0)
        If Not IsError(m) Then
            n = n + 1
            'here m = the row with the matched value, so copy from this row
        End If
    Next i
    Debug.Print "Match", Timer - t, "found " & n

End Sub

输出:

Find           19.75781     found 2000
Match          1.46875      found 2000

答案 2 :(得分:0)

如果sht没有公式单元格,则使用Variant Array会更快。

Sub test()
'Set variable with cell range value for ABC Code based on month selected by User

    Dim ABCCodeCell As Integer
    Dim wb1 As Workbook
    Dim wb2 As Workbook
    Dim sht1 As Worksheet
    Dim sht As Worksheet
    Dim lRow As Long
    Dim rng As Range

    Set wb1 = Workbooks(vFileName1) 'ABC Matrix File
    Set wb2 = Workbooks(vFileName2) 'Cycle Count Remainder Browse File
    Set sht = wb1.Worksheets(1) 'ABC Matrix File
    Set sht1 = wb2.Worksheets(1) 'Cycle Count Remainder Browse File

    lRow = sht.Cells(sht.Rows.Count, 1).End(xlUp).Row

    Select Case ABCMatrixMonthSelect.ComboBox1.Value
        Case "January": ABCCodeCell = 21
        Case "February": ABCCodeCell = 23
        Case "March": ABCCodeCell = 25
        Case "April": ABCCodeCell = 3
        Case "May": ABCCodeCell = 5
        Case "June": ABCCodeCell = 7
        Case "July": ABCCodeCell = 9
        Case "August": ABCCodeCell = 11
        Case "September": ABCCodeCell = 13
        Case "October": ABCCodeCell = 15
        Case "November": ABCCodeCell = 17
        Case "December": ABCCodeCell = 19
    End Select

    'Execute Find (Vlookup)
    Dim vDB, rngDB As Range, r As Long, c As Integer '<~~ vDB is Variant array
    Dim rngData As Range
    With sht
        r = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
        c = .Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
        Set rngDB = .Range("a2", .Cells(r, c))
        vDB = rngDB
    End With
    With sht1
        Set rngData = .Range("b1", .Range("b" & Rows.Count).End(xlUp))
    End With


    'On Error Resume Next

    For i = 1 To UBound(vDB, 1)
    'If sht.Cells(i, 1).Value <> "" Then
        If vDB(i, 1) <> "" Then
            Set rng = rngData.Find(vDB(i, 1), LookIn:=xlValues, Lookat:=xlWhole)
            If Not rng Is Nothing Then
                'sht.Cells(i, ABCCodeCell).Value = sht1.Cells(rng.Row, 9).Value
                vDB(i, ABCCodeCell) = rng.Offset(, 7)
                'sht.Cells(i, 27).Value = sht1.Cells(rng.Row, 7).Value
                vDB(i, 27) = rng.Offset(, 5)
                'sht.Cells(i, 34).Value = sht1.Cells(rng.Row, 11).Value
                vDB(i, 34) = rng.Offset(, 9)
            End If
        End If
    Next
    rngDB = vDB
End Sub