从列中查找值并快速返回其单元格的行号

时间:2015-07-27 21:15:25

标签: excel vba excel-vba

我有什么

我有一个包含零件号的文件和每个零件的几个供应商。共有1500个零件,每个零件有20个可能的供应商。为简单起见,我们假设部件列在A列中,每个供应商在此之后占据一列。供应商下的价值是手动输入的,但并不重要。

在另一张表中,我有一个从Access数据库导入的部件列表。导入零件清单,但不导入供应商信息。在这两种情况下,每个部分只出现一次。

我想做什么

我只想将第一张表中的供应商信息与导入列表中的部件相匹配。现在,我有一个功能,它通过供应商遍历列表中的每个部分,将供应商信息复制到一个数组中,在导入的部件列表中找到部件号(总是有唯一的匹配)并将数组复制到它旁边(内有供应商信息)。有用。不幸的是,每次使用它时,find函数都会显着减慢。我知道它是通过各种测试的罪魁祸首,我无法理解为什么它减慢速度(从每秒200次循环迭代开始,减慢到每秒1次并且Excel崩溃)。我可能有某种泄漏?文件大小始终为7mb。这是:

Function LigneNum(numAHNS As String) As Integer
    Dim oRange As Range, aCell As Range
    Dim SearchString As String

    Set oRange = f_TableMatrice.Range("A1:A1500")
    SearchString = numAHNS

    Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
        MatchCase:=False, SearchFormat:=False)

    If Not aCell Is Nothing Then
        'We have found the number by now:
            LigneNum = aCell.Row
        Exit Function
    Else
        MsgBox "Un numéro AHNS n'a pas été trouvé: " & SearchString
        Debug.Print SearchString & " not found!"
            LigneNum = 0
        Exit Function
    End If

End Function

该函数只返回找到该值的行号,如果找不到应该永远不会发生的行号,则返回0。

我需要帮助

我想要确定减速的原因,或者找到Find方法的替代品。我之前使用过Find,这是第一次发生在我身上。它最初取自Siddarth Rout的网站:http://www.siddharthrout.com/2011/07/14/find-and-findnext-in-excel-vba/奇怪的是它不会开始缓慢,它会随着它继续变得缓慢。

我认为使用Match可以工作,或者可能会将搜索范围(部件号)转储到数组中,并尝试将这些与导入的部件号列表相匹配。我不确定该怎么做,但我的问题更多的是关于哪一个会更快(只要它仍然不到15秒我不在乎,但是,从表单中循环超过1500项1500次是出于问题)。有人建议匹配阵列解决方案/花更多时间修复我的代码吗?

修改

这是从中调用的循环。我不认为这是有问题的:

For Each cellToMatch In rngToMatch
        Debug.Print cellToMatch.Row
        'The cellsToMatch's values are the numbers I want, rngToMatch is the column where they are.

        For i = 2 To nbSup + 1
            infoSup(i - 2) = f_TableMatrice.Cells(cellToMatch.Row, i)
        Next
        'infoSup contains the required supplier data now
        'I call the find function here to find the row where the number appears in the imported sheet
        'To copy the array nbSup on that line
        LigneAHNS = LigneNum(cellToMatch.Value) 'This is the Find function
        If LigneAHNS = 0 Then Exit Sub
        'This loop just empties the array in the right line.
        For i = LBound(infoSup) To UBound(infoSup)
            f_symix.Cells(LigneAHNS, debutsuppliers + i) = infoSup(i)
        Next

    Next

例如,如果我用LigneAHNS = 20替换LigneAHNS = LigneNum,代码执行速度非常快。泄漏因此来自find函数本身。

2 个答案:

答案 0 :(得分:3)

在不使用find函数的情况下执行此操作的另一种方法可能是这样的。首先,将部件ID及其行号放入脚本字典中。这些非常快速查找。像这样:

Dim Dict As New Scripting.Dictionary
Dim ColA As Variant
Lastrow=range("A50000").end(xlUp).Row
ColA = Range("A1:A" & LastRow).Value
For i = 1 To LastRow
    Dict.Add ColA(i, 1), i
Next i

要进一步优化,您可以将Dict声明为公共变量,填充一次,并在查找中多次引用它。我希望这比每次执行查找时在一个范围内运行一个cells.find更快。

有关在词典中查找项目的语法,请参阅Looping through a Scripting.Dictionary using index/item number

答案 1 :(得分:1)

如果您愿意为主部件表单上的每个供应商分配一个单独的列,则只能使用Excel单元格公式而不使用VB来实现此目的。然后,您可以使用条件格式使其更具视觉吸引力。我尝试了1500行,而且速度非常快。将它增加到5000行变得明显变慢,但是你说你现在只有1500行,所以它应该是合适的。

  • 在工作表1上,为每个供应商定义部件编号列和单独的列。
  • 为每个供应商创建一个单独的工作表,其中包含A列中所列供应商提供的所有部件号。确保供应商表上的行按部件号排序。
  • 将每个供应商表命名为与表1中显示的关联列标题相同。
  • 在工作表1上的每个供应商列标题下方的每个单元格中指定以下公式:

    = NOT(ISNA(VLOOKUP($ A2,INDIRECT("'"和B $ 1和;"' A:A&#34), 1,FALSE)))

以下屏幕截图显示了这一点以及条件格式,以突出显示哪些供应商具有哪些部分:

enter image description here

如果您想显示供应商提供的数量,那么您可以在供应商表单上第二列(B),其中包含每个部件的最新已知数量,并使用VLOOKUP来检索B列而不是A。