是find代替Vlookup大20k行表?

我正在研究一个由一系列表单和几个macros组成的大型项目。 我需要逐月更新的主要报告是21K行和增长。 它在12个独立的专栏中收集所有12个月的更新。 为了完成“更新”,我必须匹配包含在列“A”中的主文件(21k行是所有部件号和它们的信息)的部件号,并且将其匹配到由部件号生成的另一报告(这次包含在列“B”),如果匹配(需要紧密匹配),返回以下内容:

将第9列的值sht1放在variables指定的列中

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

将第11列的值设置为第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 

我不会评论你的代码是否是速度最好的代码,因为这不是Stack Overflow的主题,应该在Code Review上提出这样的问题。

然而,我会回答你的“(需要完全匹配)”的评论:

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

在这里输入图像说明

这些选项中的大多数(所有?)都是在下一次查找时默认记住和使用的,可以是用户执行的手动查找,也可以是VBA代码中的编程Find

您当前的查找( sht1.Range("B:B").Find(sht.Cells(i, 1).value) )除了What参数外,没有指定任何参数,因此将使用用户上次用于LookInLookAtLookIn参数的值。

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

我build议你改变你的Find是:

 Set rng = sht1.Range("B:B").Find(What:=sht.Cells(i, 1).Value, _ LookIn:=xlValues, _ LookAt:=xlWhole, _ MatchCase:=True) 

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

例如,在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 

如果sht没有公式单元格,使用Variant数组更快。

 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