Excel公式或VBA:使用2列条件在单独的表中查找匹配的地址 – 没有帮助列

我需要配方结构的帮助,

我有2桌子。 我想find一个匹配的列a和列b相等,并得到表2中的地址。它们将是唯一的条目。 举个例子:

ProjectInfoTable:

A | B | C | ------------------------------------------ 1 | Name | Company | Project | ------------------------------------------ 2 | Chris Evans | Apple | Info | ------------------------------------------ 3 | Chris Evans | Google | Info | ------------------------------------------ 4 | Bill Gates | Burger King | Info | ------------------------------------------ 

ClientInfoTable:

  A | B | C | D ------------------------------------------- 1 | Client | Company | Age | Sex | ------------------------------------------- 2 | Chris Evans | Apple | 12 | M | ------------------------------------------- 3 | Chris Evans | Google | 17 | M | ------------------------------------------- 4 | Bill Gates | Burger King | 98 | F | ------------------------------------------- 

我希望能够在'ProjectInfoTable'中获取'ClientInfoTable'中匹配的Name&Company客户端的地址,

我碰到的麻烦是可能有一千个不同的克里斯·埃文斯在那里,所以VLOOKUP在这里不是很好。 我需要通过交叉引用他们的公司来确定我在“ProjectInfoTable”中查看的“ClientInfoTable”中的Chris Evans。

我可以得到的地址没有问题,如果我只search它的名字:

 =ADDRESS(ROW(INDEX(ClientInfoTable,MATCH([@[Client]],ClientInfoTable[Client],0),1)),COLUMN(INDEX(ClientInfoTable,MATCH([@[Client]],ClientInfoTable[Client],0),1)),1,1,"Clients") 

但我需要增加公司的额外条件,所以现在公式是无用的。

有任何想法吗? 我不想使用隐藏的列或“帮助列”

我会除了VBA或公式为基础的答案。 我甚至会奖励任何能够提供这两者的人,假设数据总是dynamic范围,然后给出你的代码/公式的一个很好的解释。 我在这里学习,我不是一个复制/粘贴types的用户,解释与我长期。

你可以使用AutoFilter()

 Option Explicit Sub main() Dim rng As Range With ActiveSheet.ListObjects("ClientInfoTable").Range '<--| reference 'ClientInfoTable' range .AutoFilter field:=1, Criteria1:="Chris Evans" '<--| filter it on its 1st column with "Chris Evans" .AutoFilter field:=2, Criteria1:="Google" '<--| filter it on its 2nd column with "Google" If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then Set rng = .Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, 1) '<--| if any filtered cells other than header then set the range corresponding to upleftmost filtered cell below the headers row MsgBox "Found at " & rng.Address End If .AutoFilter '<--| show rows back visible End With End Sub 

式:

以下是只有公式的解决scheme,没有隐藏/帮助列,也没有数组公式:

 =ADDRESS( ROW( ClientInfo ) - 1 + MATCH( 1, INDEX( --INDEX( ClientInfo[Client] = $A5, 0 ) * --INDEX( ClientInfo[Company] = $B5, 0 ), 0 ), 0 ), COLUMN(ClientInfo) ) 

组件:

一个 --INDEX(ClientInfo[Client]=$A5,0) – 返回一个布尔数组,用于ClientInfo[Client]中的例如Chris Evans匹配。 在下面的例子中,这将是{TRUE,TRUE,FALSE,FALSE} 。 然后将其转换为具有双重一元运算符的整数数组,以使{1,1,0,0}

b --INDEX(ClientInfo[Company]=$B5,0) – 与例如ClientInfo[Company]中的Apple相同的例子是数组{TRUE,FALSE,FALSE,TRUE} – 然后被转换为{1,0,0,1}

c INDEX(a*b,0) – 数组a的元素1..n与数组b的元素1..n的倍数。 在我们的例子中,结果为{1,0,0,0} ,此时您已经将Chris Evans和Apple的匹配组合键标识为ClientInfo的第一行

d MATCH(1,c,0) – 获得数组中1的索引,在我们的Chris Evans和Apple的例子中是1.你提到他们将是唯一的条目,所以我不认为我们在这里有问题。

e ROW(ClientInfo)-1+d – 我将ClientInfo定义为具有A8:D12范围的Table / ListObject,但是引用返回了A9:D12 ,这似乎是它为Tables / ListObjects命名的范围工作的方式。 所以我们需要从该范围的ROW中扣除一个以获得偏移的开始; 然后简单地添加d的结果。

f ADDRESS(e,COLUMN(ClientInfo)) – 返回e的单元格地址和ClientInfo表的第一列。

例:

在这里输入图像说明

VBA:

使用上面的例子,VBA方法将执行以下操作:

  1. 假设没有find匹配
  2. 迭代表的行
  3. 获取候选值并检查引用列的input
  4. 如果两者都匹配,则退出返回地址的循环

代码:

 Option Explicit Sub Test() MsgBox GetAddressOfKey("Client", "Chris Evans", "Company", "Apple", "ClientInfo") MsgBox GetAddressOfKey("Client", "Chris Evans", "Company", "Google", "ClientInfo") MsgBox GetAddressOfKey("Client", "Bill Gates", "Company", "Burger King", "ClientInfo") End Sub Function GetAddressOfKey(col1 As String, val1 As String, col2 As String, val2 As String, strTable As String) As String Dim lst As ListObject Dim lr As ListRow Dim strAddress As String Dim strCandidate1 As String Dim strCandidate2 As String strAddress = "" Set lst = ActiveSheet.ListObjects(strTable) 'iterate rows For Each lr In lst.ListRows 'get candidate values strCandidate1 = Intersect(lr.Range, lst.ListColumns(col1).Range).Value strCandidate2 = Intersect(lr.Range, lst.ListColumns(col2).Range).Value 'check against inputs If strCandidate1 = val1 And strCandidate2 = val2 Then strAddress = lst.Range.Cells(lr.Index + 1, 1).Address 'quit if we find a match Exit For End If Next lr 'return GetAddressOfKey = strAddress End Function 

PS我很犹豫提供的VBA答案以及你已经接受了一个体面的答案。 不过,我有一个轻微的喜好做这个没有更新的UI,虽然我同意AutoFilter方法是足够好的。 HTH

解决您的问题的一种方法是通过ADODB在Excel VBA中使用SQL支持。 这篇微软文章解释了如何做到这一点。

使用SQL支持,您基本上有两种select:您可以在VBA中编写一个函数,使用SELECT语句从ClientInfoTable返回给定名称和公司的(第一个)值,或者在VBA中编写一个可直接插入的子ProjectInfoTable所有行的值,无论您需要它们,使用名称和公司上的ProjectInfoTableClientInfoTable之间的连接。

您也可以使用我写的函数。将它放到您要使用的文件中的任何模块:

 Option Compare Text Option Explicit Public Function doubleMatch(criteria1 As Range, criteria1_Range As Range, criteria2 As Range, criteria2_Range As Range) As Long Dim crit1 As Variant, crit2 As Variant Dim crit1_ARR(), crit2_ARR() 'Arrays where criteria ranges are stored Dim i As Long, j As Long Dim u1 As Long, l1 As Long crit1_ARR = criteria1_Range.Value2 crit2_ARR = criteria2_Range.Value2 crit1 = criteria1.Value crit2 = criteria2.Value doubleMatch = -1 'checking if ranges have the same height If (UBound(crit1_ARR) <> UBound(crit2_ARR)) Then GoTo endFunc End If 'checking if ranges are one col wide If (LBound(crit1_ARR, 2) <> UBound(crit1_ARR, 2)) Then GoTo endFunc End If If (LBound(crit2_ARR, 2) <> UBound(crit2_ARR, 2)) Then GoTo endFunc End If l1 = LBound(crit1_ARR) u1 = UBound(crit1_ARR) For i = l1 To u1 If (crit1 = crit1_ARR(i, 1)) Then If (crit2 = crit2_ARR(i, 1)) Then doubleMatch = i + Abs(l1 = 0) * 1 GoTo endFunc End If End If Next i endFunc: End Function 

使用示例: 在这里输入图像说明

如果有错误,则返回-1; 否则返回匹配的行数。

如果你想要完整的地址,你可以使用ADDRESS和MATCH函数一起使用这个函数:

 =ADDRESS(doubleMatch(H2;A:A;I2;B:B);MATCH("Client";A:A;0)) 

您可以将VLookUp与select结合使用以拥有多个标准。 在你的例子中:

 =VLookUp(A1&","&B1, Choose({1.2}, ClientInfoTable!A1:A4&","&ClientInfoTable!B1:B4,ClientInfoTable!C1:C4), 2, False) 

这是一个matrix公式,所以你必须用Ctrl + Shift + Enterclosures它。

接下来会发生什么:select函数select给定的第一个和第二个值(这是第一个参数{1.2}所说的)。 由于这是一个matrix公式,所以你不仅得到一对值,而且每行也有一对。 在这个例子中你得到一个matrix:

 A-----------------------|B---------- Chris Evans, Apple |12 Chris Evans, Google |17 Bill Gates, Burger King |98 

这是您现在可以用于VLookUp的matrix。

你应该确保分隔符(在这个例子中是逗号)不会出现在你的数据中。

如果您只需要地址而不是实际值,请使用函数Match而不是vlookup:

 =Match(A1&","B1, Choose({1.2}, ClientInfoTable!A1:A4&","&B1:B4,ClientInfoTable!C1:C4)) 

这返回给定matrix内对应的集合所在的行。 如果matrix不是从第1行开始,则必须添加matrix位置。

创build一个VBA函数,将客户端名称和公司作为string参数 – 然后遍历客户端表并返回地址(如果find)。 如果没有匹配,下面的代码将返回“未find#”

 Option Explicit Option Compare Text Public Function SearchAddress(clientName As String, company As String) As String Dim x As Integer Dim shtClients As Worksheet Set shtClients = Sheets("Clients") 'Clients = name of the sheet with ClientTableInfo x = 2 'loop through the clients table searching for the row where the clientname and companyname is what is supplied to the function Do 'Column A has ClientName of ClientTableInfo 'Column B has companyName of ClientTableInfo '............. 'Column E has Address of ClientTableInfo <-- our search target If shtClients.Range("A" & x).Value = clientName And shtClients.Range("B" & x).Value = company Then SearchAddress = shtClients.Range("E" & x).Value 'column E has the address in the clients info table Exit Function End If x = x + 1 Loop Until x > shtClients.UsedRange.Rows.Count SearchAddress = "Not found#" End Function 

要使用这个函数,将代码作为VBA模块导入macros工作簿(请记住启用macros)。 然后键入公式像一个正常的Excel公式一样的单元格

 =SearchAddress(ProjectInfoTable[@Name],ProjectInfoTable[@Company]) 

要么

 =SearchAddress(A1,A2)