具有多个条件的索引/匹配函数查找数组

我看了一下,但没有find有效的回应这个特定的情况。

我需要编写一个macros查找一个特定的名称(列A),材料(列B)和颜色(列C)组合,然后返回列D的价格。

我可以input公式(数组)

=INDEX(Sht1!A1:D5552,MATCH(1,(Sht1!A1:A5552=A1)*(Sht1!B1:B5552=B1)*(Sht1!G1:G5552=C1),0),4) 

其中A1有我正在search的项目的名称,B1有材料和C1有颜色,并返回值就好了。 不过,我已经设置好了在名称/材质/颜色之间快速select,我希望能够快速拉动价格,所以我试着写一个macros来运行,当我点击一个button。

我遇到的问题是将MATCH(1,(Sht1!A1:A5552 = A1) (Sht1!B1:B5552 = B1) (Sht1!C1:C5552 = C1),0)部分转置到VBA中。 我试图避免只使用loggingfunction,因为它吐出了一个R1C1格式的难以解释和更新的.ForumlaArray未来。

我努力了

 Application.Index(Sht1.Range("A1:D5552"), _ Application.Match(1, Sht1.Range("A1:A5552") = Range("A1") & _ "*" & Sht1.Range("B1:B5552") = Range("B1") & "*" & Sht1.Range("C1:C5552") = _ Range("C1"), 0), 4) 

但是得到一个types不匹配

我也尝试把.ForumlaArray中,但得到“无法设置范围类的FormulaArray属性”错误(因为它需要R1C1格式)

 "=INDEX(Sht1!A1:D5552,MATCH(1,(Sht1!A1:A5552=A1)*(Sht1!B1:B5552=B1)*(Sht1!C1:C5552=C1),0),4)" 

我的variables设置有点不同,但我试图简化这些例子,使其更容易解释。

您错误地使用了Application.Match函数和VBA的一些基础知识。 简而言之,该function不像公式那样工作。

AFAIK Application.Match需要一个值来查找,并find一维的单元格范围,并返回数组中单元格的索引。 所以这听起来像你需要多次为每一列。 当然,我找不到任何可接受的文件 。

正确的用法是:

 row_index = Application.Match(Sht1.Range("A1").Value, Sht1.Range("A1:A5552"), 0) price_value = Sht1.Cells(row_index, "D").Value 

但是,这只会返回第一场比赛,而不是所有的比赛。 如果您正在使用VBA中的复制公式,则VBA不会提高性能。 其他海报是正确的,可能需要一个不同的方法。


你错误的一些其他的基本原则主要来自你采取公式string,并试图直接翻译成Application.Match AFAIK你不能做的。

你正在试图指定你有这样一个匹配的条件:

 Sht1.Range("A1:A5552") = Range("A1") 

你真正在做的是试图比较范围。 VBA正在试图评估这是一个布尔值,然后将其传递给Application.Match 。 这将返回一个types错误,因为范围是不同的维度。

如果您还没有这样做: Sht1需要被声明为Worksheet对象并设置为ActiveWorkbook.Sheets("Sht1")

 Dim Sht1 As WorkSheet Set Sht1 = ActiveWorkbook.Sheets("Sht1") 

你不能简单地希望variablesSht1已经指向工作表“Sht1”。

然后你试着把这些串起来

 Sht1.Range("A1:A5552") = Range("A1") & "*" & _ Sht1.Range("B1:B5552") = Range("B1") & "*" & _ Sht1.Range("C1:C5552") = Range("C1") 

我想你明白, &是为string连接,但你正试图连接,string"*"与布尔值/范围是未定义的。

一个VBA解决scheme

如果您想要使用VBA的解决scheme,则可以遍历所有行,直到find匹配项为止:

 Function FindProduct(name As String, material As String, color As String) As String Dim product_sheet As WorkSheet Set product_sheet = GetProductSheet() ' Workbooks(BOOK_NAME).Sheets(SHEET_NAME) Dim row_index as Long For row_index = 2 To product_sheet.UsedRange.Rows.Count If product_sheet.Cells(row_index, NAME_COL).Value = name _ And product_sheet.Cells(row_index, MATERIAL_COL).Value = material _ And product_sheet.Cells(row_index, COLOR_COL).Value = color Then FindProduct = product_sheet.Cells(row_index, PRODUCT_COL).Value Exit Function End If Next row_index End Function 

或者如果性能是一个问题:

  • 保持你的数据在列“A”,“B”,“C”(对于这个例子,依次)。
  • find列“A”中匹配的行的范围
  • 在该范围内,find在列“B”中匹配的行的子范围
  • 在该范围内,返回在列“C”中匹配的行的子范围

我可以稍后提供。

我认为你会用完全不同的方法来改善。 而不是让VBA执行查找,我会使用VBA维护表列中唯一值的列表,每个列都包含在一个命名范围内。 然后使用“数据validation”为VBA创build的命名范围填充的每个search项目(名称,材料,颜色)创build一个下拉菜单,并继续使用上面列出的数组公式,以执行实际查找。

请参阅Jean-FrançoisCorbett的答案,了解如何从Excel中将唯一值填充到VBA数组中 。

使用一个Table结合结构化引用 ,你可以添加更多的条目到你的Table的底部,它会自动地神奇地扩大到包括他们。 设置您的VBA代码, ColorListTable更改时生成唯一值的新列表(并将其存储在命名范围内,例如NamesListMaterialsListColorList )。

另一个select是简单地使用数据透视表。

编辑: 这是另一个很好的方法来build立一个Range的唯一值的列表。