Excel结合了Vlookups

我有两个文件,一个是项目registry,它包含关于项目的关键信息,另一个是风险日志。

registry和风险日志中的条目之间有1:m的关系。 我需要做的是将所有项目风险合并到项目注册文件中的一个单元格中。

这两个文件中的匹配字段是项目ID字段

有没有一种方法可以使用vlookup变体或多个嵌套的vlookups来做到这一点?

这里是我提到的用户定义的函数方法(改编自我已经做过的不同的VLOOKUP变体):

 ' Acts like VLOOKUP in a 1-to-many scenario by concatenating all values in matching rows ' instead of just returning the first match Public Function VLOOKUP_MANY(lookup_value As String, lookup_range As Range, column_number As Integer, Optional delimiter As Variant) As Variant Dim vArr As Variant Dim i As Long Dim found As Boolean: found = False ' Set default delimiter If IsMissing(delimiter) Then delimiter = ", " ' Get values vArr = lookup_range.Value2 ' If column_number is outside of the specified range, return #REF If column_number < LBound(vArr, 2) Or column_number > UBound(vArr, 2) Then VLOOKUP_MANY = CVErr(xlErrRef) Exit Function End If ' Search for matches and build a concatenated list VLOOKUP_MANY = "" For i = 1 To UBound(vArr, 1) If UCase(vArr(i, 1)) = UCase(lookup_value) Then VLOOKUP_MANY = VLOOKUP_MANY & delimiter & vArr(i, column_number) found = True ' Mark at least 1 result End If Next If found Then VLOOKUP_MANY = Right(VLOOKUP_MANY, Len(VLOOKUP_MANY) - Len(delimiter)) ' Remove first delimiter Else VLOOKUP_MANY = CVErr(xlErrNA) ' If no matches found, return #N/A End If End Function 

这将search指定范围中的第一列作为指定的值(与VLOOKUP相同),但是会返回指定列号中串联的值。 当没有find匹配时,它将返回#N / A;如果为列号指定了一个无效值(例如,select第5列,但只有一个4列表),则返回#REF。

如果您不知道用户定义的函数,则可以将此VBA代码复制到工作簿中模块的VBE中。 点击Alt + F11,进入屏幕顶部的Insert > Module ,然后将该代码粘贴到打开的空白文件中。 当您保存时,您必须将工作簿保存为启用macros(.xlsm)以保持代码正常工作–Excel会在保存屏幕中提醒您。

应该预先警告:由于必须查看整个查找范围,而不是在发现的第一个匹配时停下来,所以比VLOOKUP要慢。

如果您打算使用数组公式来加速这种对于非常大的数据集的function…


不同的版本,利用数组公式的一些好处来存储查找值并加速后续调用:

 ' Acts like VLOOKUP in a 1-to-many scenario by concatenating all values in matching rows ' instead of just returning the first match ' Utilizes a dictionary to speedup multiple matches (great for array formulas) Public Function VLOOKUP_MANY_ARRAY(lookup_values As Range, lookup_range As Range, column_number As Integer, Optional delimiter As Variant) As Variant Dim vHaystack As Variant, vNeedles As Variant Dim i As Long Dim found As Boolean: found = False Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary") ' Set default delimiter If IsMissing(delimiter) Then delimiter = ", " ' Get values vHaystack = lookup_range vNeedles = lookup_values ' If column_number is outside of the specified range, return #REF If column_number < LBound(vHaystack, 2) Or column_number > UBound(vHaystack, 2) Then VLOOKUP_MANY_ARRAY = CVErr(xlErrRef) Exit Function End If ' Add values to a lookup dictionary For i = 1 To UBound(vHaystack, 1) If dict.Exists(UCase(vHaystack(i, 1))) Then dict.Item(UCase(vHaystack(i, 1))) = dict.Item(UCase(vHaystack(i, 1))) & delimiter & vHaystack(i, column_number) Else dict.Add UCase(vHaystack(i, 1)), vHaystack(i, column_number) End If Next Dim outArr As Variant If IsArray(vNeedles) Then ' Check number of lookup cells ' Build output array ReDim outArr(1 To UBound(vNeedles, 1), 1 To 1) As Variant For i = 1 To UBound(vNeedles, 1) If dict.Exists(UCase(vNeedles(i, 1))) Then outArr(i, 1) = dict.Item(UCase(vNeedles(i, 1))) Else outArr(i, 1) = CVErr(xlErrNA) End If Next Else ' Single output value If dict.Exists(UCase(vNeedles)) Then outArr = dict.Item(UCase(vNeedles)) Else outArr = CVErr(xlErrNA) End If End If VLOOKUP_MANY_ARRAY = outArr End Function 

这创build了一个Dictionary ,这是一个特殊的结构,非常适合查找值。 构build它需要额外的一些额外的开销,但是一旦你有了结构,你就可以快速地进行查询。 对于数组公式而言,这是非常好的,基本上当完全相同的公式被放入一个完整的单元集合中时,函数执行一次并为每个单元格返回值(而不是仅仅为一组单元格执行一次)。 使用CTRL + SHIFT + ENTER键input数组公式,并使第一个参数指向所有查找值而不是一个。

它将在不被用作数组公式的情况下工作,但是在这种情况下它将比第一个函数慢一些。 但是,如果在数组公式中使用它,则会看到巨大的加速。

重新编辑:

您可能需要编写一个用户定义的函数或写一个macros(代码在同一链接上)