简体   繁体   English

在Excel VBA VLookup函数中使用索引和匹配

[英]Using Index and Match in Excel VBA VLookup function

I have an excel formula that I use often that does a VLookup . 我有一个excel公式,我经常使用它做一个VLookup It has an embedded Index/Match that gives the last numeric value in the "M" Column. 它有一个嵌入的Index/Match ,它给出“M”列中的最后一个数值。
The Worksheet formula is this: 工作表公式是这样的:

=VLOOKUP(INDEX($M$10:$M75,MATCH(9.99999999999999E+307,$M$10:$M75)),Data,4)

Cell $M75 being the cell of the row this formula is in. There are numeric, non-numeric and blank cells in Column M but the ID's that I want are always numeric. 单元格$M75是此公式所在行的单元格。列M中有数字,非数字和空白单元格,但我想要的ID始终为数字。

So I am trying to write a custom function that would let me simply write =current() 所以我试着写一个自定义函数,让我简单地写=current()

Here is what I have: 这是我有的:

Function Current()
  Dim LookupRange As Variant
  Dim indexVar As Variant
  LookupRange = Range("$M$1:M" & ActiveCell.Row)
  indexVar = Application.Index(Range(LookupRange), Application.Match(9.99999999999999E+307, Range(LookupRange)))
  Current = Application.WorksheetFunction.VLookup(indexVar, Worksheets("Info").Range("Data"), 4)
End Function

I have tried using different variable types (String, Long, Variant) but I can't seem to get the function to work. 我尝试使用不同的变量类型(String,Long,Variant),但我似乎无法使函数工作。
I don't know if this is enough info but can anyone see if I am missing something? 我不知道这是否足够信息,但任何人都可以看到我是否遗漏了什么?
I only get #VALUE! 我只得到#VALUE!
Using Excel 2013 on Windows 7 在Windows 7上使用Excel 2013

There are some problems with this code that are at odds with your description. 此代码存在一些与您的描述不一致的问题。

  • LookupRange is a variant array. LookupRange是一个变体数组。 When I test this, it raises a 1004 Method 'Range' of object '_Global' failed error in the assignment to indexVar . 当我测试它时,它在indexVar的赋值中引发了1004 Method 'Range' of object '_Global' failed错误的1004 Method 'Range' of object '_Global' failed
  • If I Dim LookupRange As String per your comments, I also get a Type Mismatch error. 如果我根据你的评论Dim LookupRange As String ,我也会收到Type Mismatch错误。

Since LookupRange should be a range, I declare it as a range, and use the Set keyword in the assignment statement. 由于LookupRange应该是一个范围,我将其声明为范围,并在赋值语句中使用Set关键字。

Set lookupRange = Range("$M$10:$M" & ActiveCell.Row)
  • Possible typo in your assignment to lookupRange . 您对lookupRange的分配可能存在拼写错误。 In your formula, originally you use $M$1 , but in the function you use $M$10 . 在你的公式中,最初使用$M$1 ,但在函数中你使用$M$10

If you start this range at $M$10 , and try to evaluate the formula in any cell between row 1-9, you will get an error. 如果您以$M$10开始此范围,并尝试在第1-9行之间的任何单元格中评估公式,则会出现错误。

On a related note, if there are no numeric values in the lookupRange , this will return an error, eg, putting Current() in cell M2 makes a lookup range of M1:M2 , wherein I have no numeric data. 在相关的说明中, 如果 lookupRange 中没有数值 ,则这将返回错误,例如,将单元格M2 Current()置于M1:M2的查找范围内,其中我没有数字数据。

在此输入图像描述

I am not sure how you want to handle this, but my answer includes one way to avoid that error. 我不确定你想怎么处理这个,但我的答案包括一种避免这种错误的方法。 You can modify as needed. 您可以根据需要进行修改。 Finally: 最后:

  • Relying on ActiveCell.Row seems like a bad idea, since this formula may recalculate with undesired results. 依赖ActiveCell.Row似乎是一个坏主意,因为这个公式可能会重新计算不良结果。

Instead, make this a required argument for the formula, which you can then call from the worksheet like: =Current(Row()) . 相反,将其设为公式的必需参数,然后可以从工作表调用,如: =Current(Row())

Putting it all together, I think this should work, and I provide an example/escape for the match not found error. 把它们放在一起,我认为这应该工作,我提供了一个示例/转义匹配未找到错误。 :

Public Function Current(r As Long)
    Const bigNumber As Double = 9.99999999999999E+307
    Dim wsInfo As Worksheet: Set wsInfo = Worksheets("Info")
    Dim lookupRange As Range
    Dim indexVar As Long
    Dim myVal As Variant

    Set lookupRange = Range("$M$1:$M" & r)
    If Not Application.WorksheetFunction.Sum(lookupRange) = 0 Then
        indexVar = Application.Index(lookupRange, Application.Match(bigNumber, lookupRange))
        myVal = Application.WorksheetFunction.VLookup(indexVar, wsInfo.Range("Data"), 4)
    Else:
        myVal = "No numbers found in: " & lookupRange.Address
    End If
    Current = myVal

End Function

UPDATE FROM COMMENTS 评论的更新

You can add Application.Volatile link before the variable declarations. 您可以在变量声明之前添加Application.Volatile 链接 This should force re-calculation: 这应该强制重新计算:

whenever calculation occurs in any cells on the worksheet. 只要在工作表上的任何单元格中进行计算。

However, this will not force calculation when values on other worksheets (eg, your Worksheets("Info") is another worksheet) change. 但是,当其他工作表上的值(例如,您的Worksheets("Info")是另一个工作表)更改时,这不会强制计算。

To force recalculation every time you active the sheet containing the =Current(Row()) function, you could put this in the worksheet's code module: 要在每次激活包含=Current(Row())函数的工作表时强制重新计算,可以将其放在工作表的代码模块中:

Private Sub Worksheet_Activate()
    Me.Calculate
End Sub

This is probably as close as you can get -- to replicating the native VLOOKUP functionality without actually using a VLOOKUP formula. 这可能就像你可以得到的那样 - 复制本机VLOOKUP功能而不实际使用VLOOKUP公式。

Additional notes: 补充笔记:

Favoring correctly/strongly-typed variables, I declare indexVar as Long and create a double-precision variable for 9.99999999999999E+307 (it's just easier to work with this way). 偏好正确/强类型变量,我将indexVar as Long声明indexVar as Long并为9.99999999999999E+307创建一个双精度变量(这样更容易使用)。 I also create a worksheet object variable, again, I find them easier to work with. 我还创建了一个工作表对象变量,我再次发现它们更容易使用。

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

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