简体   繁体   English

在 Microsoft Excel 中使用 VBA Function 进行索引匹配

[英]Index Match using VBA Function in Microsoft Excel

I'm new to Excel VBA and am trying to write a function that lets me use INDEX , MATCH and COUNTIFS functions to find value for a given column by matching criteria in other columns (multiple).我是 Excel VBA 的新手,我正在尝试编写一个 function 让我在其他列中使用INDEXMATCHCOUNTIFS函数来查找多个匹配值。

I have a table named Price which contains some prices offered in different locations based on an assigned category:我有一个名为Price的表,其中包含基于指定类别在不同位置提供的一些价格:

Area    Category    Cost    Retail Price    Wholesale Price
USA Bad 1   13  25
Canada  Okay    2   14  26
Mexico  Good    3   15  27
USA Excellent   4   16  28
Canada  Bad 5   17  29
Mexico  Okay    6   18  30
USA Good    7   19  31
Canada  Excellent   8   20  32
Mexico  Bad 9   21  33
USA Okay    10  22  34
Canada  Good    11  23  35
Mexico  Excellent   12  24  36

In Excel I can use the an array formula to get this (see video example here ).在 Excel 中,我可以使用数组公式来获得它(请参见此处的视频示例)。 The below formula lets me get Wholesale Price for Okay category in Mexico下面的公式让我得到Mexico Okay类别的Wholesale Price

{=INDEX(Price,MATCH(1,COUNTIFS(L12,Price[Area],M12,Price[Category]),0),MATCH(N12,Price[#Headers],0))}

Where在哪里

L12 = Mexico
M12 = Okay 
N12 = Wholesale Price 

I'd like to make a VBA function ProdPrice that can return this value without a messy-looking formula.我想制作一个 VBA function ProdPrice ,它可以返回这个值,而没有一个看起来凌乱的公式。 Here's what I have so far:这是我到目前为止所拥有的:

Function ProdPrice(locs, cat, pricetype)
    
    'Get column number corresponding to selected "pricetype"
    col_num = WorksheetFunction.Match( _
                pricetype, _
                ActiveSheet.ListObjects("Price").HeaderRowRange.Select, _
                0)
                
    ProdPrice = WorksheetFunction.Index( _
                    ActiveSheet.ListObjects("Price"), _
                    WorksheetFunction.Match( _
                        1, _
                        WorksheetFunction.CountIfs( _
                            ActiveSheet.ListObjects("Price").ListColumns("Area").DataBodyRange.Select, _
                            locs, _
                            ActiveSheet.ListObjects("Price").ListColumns("Category").DataBodyRange.Select, _
                            cat), _
                        0), _
                    col_num)

End Function

Instead of a single call, I broke the function into two segments with _ for better readability.为了更好的可读性,我将_分成两个部分,而不是单个调用。

When I run this I get a #VALUE!当我运行它时,我得到一个#VALUE! output. output。

Any suggestions on how I can go about this?关于我如何 go 对此有何建议? Also from what I understand, the above function will look for a table called price in the worksheet where the function is called - I'd like for it to be able to look at price in the workbook instead.同样据我了解,上述 function 将在工作表中查找名为price的表,其中 function 被调用 - 我希望它能够在工作簿中查看price

I assume that your values are always in an Excel structured table我假设您的值始终在 Excel 结构化表中

Remarks:评论:

  • Function is case insensitive Function不区分大小写
  • Table headers and values don't contain |表头和值不包含| character特点
  • Function will return first matching value ( area and category ) Function 将返回第一个匹配值( areacategory
  • Columns order doesn't care列顺序无关紧要

Please read code's comments and adjust it to fit your needs请阅读代码的注释并根据您的需要进行调整

Code代码

Public Function lookupPrice(ByVal table As Range, ByVal lookup_area As String, ByVal lookup_category As String, ByVal pricetype_header As String) As Variant
    
    ' Define column headers
    Dim areaHeader As String
    Dim categoryHeader As String
    areaHeader = "Area"
    categoryHeader = "Category"
    
    ' Get area column number from headers
    Dim areaColumn As Long
    areaColumn = Application.Match(areaHeader, table.ListObject.HeaderRowRange, False)
    
    ' Get category column number from headers
    Dim categoryColumn As Long
    categoryColumn = Application.Match(categoryHeader, table.ListObject.HeaderRowRange, False)
    
    ' Get price column number from headers according to function parameter
    Dim priceColumn As Long
    priceColumn = Application.Match(pricetype_header, table.ListObject.HeaderRowRange, False)
    
    
    ' Get area column values into 1d array
    Dim areaValues As Variant
    areaValues = WorksheetFunction.Transpose(Application.Index(table.Columns(areaColumn), 0, 1))
    
    ' Get category column values into 1d array
    Dim categoryValues As Variant
    categoryValues = WorksheetFunction.Transpose(Application.Index(table.Columns(categoryColumn), 0, 1))
    
    ' Define and redimension an array to hold the concatenated area and category values
    Dim areaCategoryValues() As Variant
    ReDim areaCategoryValues(1 To UBound(areaValues))
    
    ' Concatenate the area and category values and store them in an array
    Dim counter As Long
    For counter = 1 To UBound(areaValues)
        areaCategoryValues(counter) = areaValues(counter) & "|" & categoryValues(counter)
    Next counter
    
    ' Get the matching row according to lookup values
    Dim resultRow As Long
    resultRow = Application.Match(lookup_area & "|" & lookup_category, areaCategoryValues, False)
    
    ' Get the result value according to the price column number
    Dim result As Variant
    result = Application.Index(table.Columns(priceColumn), resultRow)
    
    ' Return the value
    lookupPrice = result
    
End Function

Let me know if it works让我知道它是否有效

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

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