我有两个文件,一个是项目注册表,它包含关于项目的关键信息,另一个是风险日志。Excel合并Vlookups
注册表和风险日志中的条目之间存在1:m的关系。我需要做的是将所有项目风险合并到项目寄存器文件中的一个单元格中。
匹配场这两个文件是项目ID字段
有没有一种方法,我可以做到这一点使用VLOOKUP变体或多重嵌套vlookups?
我有两个文件,一个是项目注册表,它包含关于项目的关键信息,另一个是风险日志。Excel合并Vlookups
注册表和风险日志中的条目之间存在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
这将在指定的值(与VLOOKUP)指定的搜索范围内的第一列,但在指定的列数级联返回值。当找不到匹配时,它将返回#N/A;如果为列号指定了无效值(例如,选择第5列,但只有4列表),则返回#REF。
如果您不知道用户定义的函数 - 您可以将此VBA代码复制到工作簿中模块的VBE中。点击Alt + F11,转到屏幕顶部的Insert > Module
,然后将此代码粘贴到打开的空白文件中。当您保存时,您必须将工作簿保存为启用宏(.xlsm)以保持代码正常工作--Excel会在保存屏幕中提醒您这一点。
预先警告:由于必须查看整个查找范围,而不是能够在找到的第一个匹配处停下来,所以会比VLOOKUP慢。
如果你打开使用数组公式代替,有办法加快这种非常大的数据集的功能...
,它利用一些阵列的利益不同版本公式存储查找值和加速后续调用:
' 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
这将创建一个Dictionary
,这是一种特殊的结构,这对查找值确实不错。构建它需要额外的一些额外开销,但是一旦你拥有了结构,你就可以很快地进行查找。这对于数组公式尤其好,基本上当同一个公式被放入一个完整的单元集合中时,那么该函数执行一次并为每个单元返回值(而不是仅针对一堆执行一次的细胞)。像使用CTRL + SHIFT + ENTER的数组公式一样输入它,并使第一个参数指向所有您的查找值而不是一个。
它可以在不用作数组公式的情况下工作,但它会比那种情况下的第一个函数慢一些。但是,如果你在一个数组公式中使用它,你会看到巨大的加速。
重新编辑:
您可能需要编写一个user defined function或写一个宏(在相同的链接代码)
我这么认为,但可能并不美观。'VLOOKUP'只提供一个值,如果你知道风险的最高可能值'm',则可以使用'm'嵌套'VLOOKUP'。 –
这与VLOOKUP完成有多重要?如果愿意,VBA用户定义的函数可以完成所有这些。 – Mikegrann