简体   繁体   English

VBA:VLookUp多重结果

[英]VBA: VLookUp Multiple Results

I require a little help with some code. 我需要一些代码的帮助。

I am trying to perform a VLookup, and has the data displayed in columns O, P and Q. 我正在尝试执行VLookup,并将数据显示在O,P和Q列中。

What i am trying to do is loop though sheet("Global") column A starting at row 3 until last used row. 我想要做的是循环通过工作表(“全局”)列A从第3行开始直到最后使用的行。 It needs to match data in sheet("Details") in column A starting at row 2. 它需要匹配从第2行开始的A列表中的数据(“详细信息”)。

So when it finds a matching value, it will display the results from "Details" C2 in "Global" O2, "Details" I2 in "Global" P2 and "Details" G2 in "Global" Q2. 因此,当它找到匹配值时,它将显示“全局”O2中的“详细信息”C2,“全局”P2中的“详细信息”I2和“全局”Q2中的“详细信息”G2中的结果。

It then needs to loop though "Global" matching and copying all data. 然后它需要循环“全局”匹配并复制所有数据。 If no match is found the display "NA!". 如果未找到匹配项,则显示“NA!”。

The last thing I need it to do is to delete all rows in Global where a match was not found. 我需要它做的最后一件事是删除未找到匹配项的Global中的所有行。

The code I have below does what I need, the only problem is that it is incredibly slow, taking minutes to loop though 800 rows, sometimes even longer!! 我下面的代码做了我需要的,唯一的问题是它非常慢,需要几分钟才能循环800行,有时甚至更长!

Is there another way to do this, that will run smoother and faster? 还有另一种方法可以做到这一点,它会更顺畅,更快速地运行吗?

Any help is appreciated!! 任何帮助表示赞赏!!

Thank You 谢谢

`Private Sub btnVlookUp_Click()
Dim i, j, lastG, lastD As Long

' find last row
lastG = Sheets("Global").Cells(Rows.Count, "B").End(xlUp).Row
lastD = Sheets("Details").Cells(Rows.Count, "A").End(xlUp).Row

' loop over values in "Global"
For i = 3 To lastG
    lookupVal = Sheets("Global").Cells(i, "B") ' value to find

    ' loop over values in "details"
    For j = 2 To lastD
        currVal = Sheets("Details").Cells(j, "A")

        If lookupVal = currVal Then
            Sheets("Global").Cells(i, "O") = Sheets("Details").Cells(j, "C")
            Sheets("Global").Cells(i, "P") = Sheets("Details").Cells(j, "I")
            Sheets("Global").Cells(i, "Q") = Sheets("Details").Cells(j, "G")
            ' mark the row
            Sheets("Details").Cells(j, "Z") = "marked"

        End If
    Next j
Next i

' loop over rows in "details" and delete rows which have not been marked
For j = 2 To lastD
    If Sheets("Details").Cells(j, "Z") <> "marked" Then
        ' delete unmarked rows
        Sheets("Details").Cells(j, "A").EntireRow.Delete
        If Sheets("Details").Cells(j, "B") <> "" Then
            j = j - 1 ' revert iterator so it doesn't skip rows
        End If
    Else:
        ' remove the mark
        Sheets("Details").Cells(j, "Z") = ""
    End If
Next j
End Sub`

With the advice on here, and a lot of trial and error, i have managed to tweak my code. 根据这里的建议,以及大量的试验和错误,我设法调整了我的代码。

I tested this on over 600 records and it runs in seconds, where it would have taken minutes on the previous code. 我在超过600条记录上对此进行了测试,并在几秒钟内运行,在上一段代码中需要几分钟。

If you can see a better way of doing the below code, then let me know, i'm still learning VBA so all the help I can get the better!!! 如果你能看到更好的方法来做下面的代码,那么让我知道,我还在学习VBA所以所有的帮助我可以变得更好!

Thanks for all the support!!!!!!!! 感谢所有的支持!!!!!!!!

Private Sub btnVlookUp_Click()
Dim i, j, lastG, lastD As Long
With Application
    .ScreenUpdating = False
    .EnableEvents = False
    .CutCopyMode = False
End With
' find last row
lastG = Sheets("Global").Cells(Rows.Count, "B").End(xlUp).Row
lastD = Sheets("Details").Cells(Rows.Count, "A").End(xlUp).Row

' loop over values in "Global"
For i = 2 To lastG
    lookupVal = Sheets("Global").Cells(i, "B") ' value to find

    ' loop over values in "details"
    For j = 2 To lastD
        currVal = Sheets("Details").Cells(j, "A")

        If lookupVal = currVal Then
            Sheets("Global").Cells(i, "O") = Sheets("Details").Cells(j, "C")
            Sheets("Global").Cells(i, "P") = Sheets("Details").Cells(j, "I")
            Sheets("Global").Cells(i, "Q") = Sheets("Details").Cells(j, "G")
            ' mark the row
            Sheets("Details").Cells(j, "Z") = "marked"
            Sheets("Details").Cells(1, "Z") = "marked"
        Exit For
        End If
    Next j
Next i

On Error Resume Next
Sheets("Details").Columns("Z").SpecialCells(xlBlanks).EntireRow.Delete
Sheets("Details").Columns("Z").ClearContents

With Application
    .ScreenUpdating = True
    .EnableEvents = True
    .CutCopyMode = True
End With

End Sub

Your code is very inefficient as written, which is why it takes forever. 您编写的代码效率非常低,这就是为什么它需要永远。 You didn't mention specifically how many rows are in your "Global" and "Detail" sheets (you mentioned 800, not sure if this is both). 您没有具体提到“全局”和“详细信息”表中有多少行(您提到800,不确定这两者是否相同)。 But if there were 1000 in each, your two loops are 1000x1000 = 1 million cycles. 但如果每个都有1000个,那么你的两个循环是1000x1000 = 100万个循环。

The best solution is not to use VBA at all, but use the VLOOKUP function in Excel. 最好的解决方案是根本不使用VBA,而是在Excel中使用VLOOKUP函数。 Here's what you need to do: 这是你需要做的:

Sort the Details sheet by Column A Then, in the Global sheet, in cell O3, you'll put the following formula: =VLOOKUP(A3,Details!$A2:$I(whatever the last row is),3,FALSE) 按列A对详细信息表进行排序然后,在全局表单的单元格O3中,您将放置以下公式:= VLOOKUP(A3,详细信息!$ A2:$ I(无论最后一行是什么),3,FALSE)

In case you're not familiar with this function, it takes the first argument, looks it up in the first column of the second argument until it finds a match, and then returns the value in that row at the column of the third argument. 如果您不熟悉此函数,它将获取第一个参数,在第二个参数的第一列中查找它,直到找到匹配项,然后在第三个参数的列中返回该行中的值。 The last "FALSE" gives you only an exact match, else you'll get an #NA (if you use TRUE, you'll get the closest match instead). 最后一个“FALSE”只给你一个完全匹配,否则你会得到一个#NA(如果你使用TRUE,你会获得最接近的匹配)。

Then copy this formula down the entire sheet. 然后将此公式复制到整个工作表中。

Then copy the column, and paste values. 然后复制列,并粘贴值。 This gets rid of the forumlas and just leaves the values, which makes everything much faster. 这摆脱了论坛,只留下了价值观,这使得一切都变得更快。

Then sort the table by this column, and all of the #NA will fall together, and you can delete the whole thing in one operation. 然后按此列对表进行排序,并且所有#NA将合在一起,您可以在一个操作中删除整个事物。

If you want to do this via VBA, the steps above can easily be coded: 如果您想通过VBA执行此操作,可以轻松编写上述步骤:

Private Sub btnVlookUp_Click()
Dim i, j, lastG, lastD As Long
Dim DetailsTable as Range

' find last row
lastG = Sheets("Global").Cells(Rows.Count, "B").End(xlUp).Row
lastD = Sheets("Details").Cells(Rows.Count, "A").End(xlUp).Row

' Make sure this is sorted.  If not, you'll need to add a sort command
Set DetailsTable=Sheets("Details").Range(Sheets("Details").Cells(1, 2), Sheets.Cells(lastD, 9))

Sheets("Global").Range("O3")="=VLOOKUP(A3," & DetailsTable.address(external:=true) & "3,FALSE)"
Sheets("Global").Range("O3").copy destination:=Sheets("Global").Range( Sheets("Global").cells(3,"O"),Sheets("Global").cells(lastG,"O"))

End Sub

This is a start, but should get you going. 这是一个开始,但应该让你去。 Good luck! 祝好运!

There are a couple things that you could do to easily speed up your code. 您可以采取一些措施来轻松加快代码速度。

First off, if you add the line Application.ScreenUpdating = False at the beginning of your code, it will stop Excel from having to do all of the flickers and flashes that you see while executing your code (which is actually adding in those values one by one, deleting rows, etc. all which take a lot of time). 首先,如果在代码开头添加Application.ScreenUpdating = False行,它将使Excel不必执行您在执行代码时看到的所有闪烁和闪烁(实际上是在添加这些值之一)一个,删除所有花费很多时间的行等。

Next, you can add an Exit For at the end of your If statement (right before your End If ). 接下来,您可以在If语句的末尾添加一个Exit For (在End If之前)。 This will stop the nested For Loop to prevent running through all of the data when you've already found what you're looking for. 这将停止嵌套的For循环,以防止在您找到所需内容后运行所有数据。

Lastly, I know that you use j = j - 1 to set your iterator to not skip over rows, but a better practice is to instead work the opposite direction. 最后,我知道您使用j = j - 1来设置迭代器以不跳过行,但更好的做法是改为相反的方向。 If you change the For Loop to read For j = lastD to 2 Step -1 it will make the Loop run in reverse, so deleted rows aren't an issue and you can remove the "reset" line (this will only barely speed up your code, it's just more of a suggestion of how to deal with this common problem). 如果将For循环更改为读取For j = lastD to 2 Step -1它将使循环反向运行,因此删除的行不是问题,您可以删除“重置”行(这只会勉强加速你的代码,它只是建议如何处理这个常见问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM