我希望基于匹配的列值在Excel电子表格中对两个不同的表进行内部联接。这是一个示例:
表A:
TICKER
AAPL
AMZN
FB
MSFT
TWLO
表B:
TICKER PRICE
AAPL 100
FB 200
TSLA 300
DIS 400
内部联接应返回表B中的报价和表B中的价格:
TICKER PRICE
AAPL 100
FB 200
我已经尝试过VLOOKUP
和MATCH
,但是无法模拟INNER JOIN
中存在的SQL
函数。希望StackOverflow社区可以提供一些帮助:)
答案 0 :(得分:3)
为此,您需要两个不同的公式:
要获取您想要的名称,
=IFERROR(INDEX(C:C,AGGREGATE(15,6,ROW($C$2:$C$5)/(ISNUMBER(MATCH($C$2:$C$5,A:A,0))),ROW(1:1))),"")
要获取值:
=IF(G2<>"",VLOOKUP(G2,C:D,2,FALSE),"")
这可以用一个公式完成:
=IFERROR(INDEX($C:$D,AGGREGATE(15,6,ROW($C$2:$C$5)/(ISNUMBER(MATCH($C$2:$C$5,$A:$A,0))),ROW(1:1)),COLUMN(A:A)),"")
将其放入G2,然后上下复制。
但是这会使数组公式的数量增加一倍,如果数据集很大,则会导致计算时间显着降低。
答案 1 :(得分:2)
如果您需要SQL,请使用它! :)
这是使用SQL连接表的VBA代码示例。这是sample workbook和代码。将创建带有结果的新表。假设表A在Sheet1上,表B在Sheet2上:
Sub JoinTables()
Dim x%
Dim rs As Object
Dim sql$, connString$
connString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 12.0;HDR=Yes;"""
Set rs = CreateObject("ADODB.Recordset")
sql = "SELECT z.* FROM [Sheet1$] x INNER JOIN [Sheet2$] z ON x.TICKER = z.TICKER;"
rs.CursorLocation = 3 'adUseClient
rs.Open sql, connString, 0, 1
If rs.RecordCount > 0 Then
With Sheets.Add(After:=Sheets(Sheets.Count))
'// Dump header
For x = 0 To rs.Fields.Count - 1
.Cells(1, x + 1) = rs(x).Name
Next
.Range("A2").CopyFromRecordset rs
End With
Else
MsgBox "No records were found.", vbExclamation
End If
rs.Close
Set rs = Nothing
MsgBox "Well done!", vbInformation
End Sub
答案 2 :(得分:2)
正如使用powerquery所指出的那样,这非常容易,您可以在将两个表都存储在内存中之后使用合并查询功能内部连接两个表。
为另一个表重复步骤2-4,这样两个表都在内存中。
答案 3 :(得分:1)
好吧,这是Catch 22 ...因为它可以同时进行,而且不能同时完成
在此之下我的意思是,Excel主要用于静态数据。尽管结果可能会根据公式而有所不同,但为了检查值,需要在某个地方指定该值。
内部联接是一种基本上需要两个实体并从中创建一个新实体的操作,如下所示:
正如@ScottCraner正确指出的那样,这不是Excel要做的。这样我们就有3个选择(或者至少我能想到很多)。
重要的是要指出我们甚至没有能力做适当的INNER JOIN()
,但我们至少可以制造一种错觉-基本上是对它应该做什么的模仿
手动方式-我写了一个答案,但@ScottCraner击败了我,我敢说这很优雅,所以直接参考他的话
vba方式-我将在下面回答
通过powerquery -我对自己不太熟悉,因此您必须进行自己的研究,也许其他人会回答。
假设我们有以下数据:
如果我们要描述INNER JOIN()
如何以算法的方式工作,它将看起来像这样。
a
b
比较数据并返回新的结果数组r = a ∩ b
3.1表达式a ∩ b
可以按以下方式“以编程方式”编写:
For
a
中的每个元素:if
和exists
中的b
push
到r
结果数组Next
元素r
结果数组现在,出于简单起见(出于实际使用),我将不返回数组。我要做的是,如果条件符合条件,则打印列F
中的每个元素(基本上执行步骤1.
至3.
)
Option Explicit
Private Sub INNER_JOIN(ByVal range1 as Range, ByVal range2 as Range)
Dim ws as Worksheet: Set ws = Sheets("Your Sheet Name")
Dim lr as Long 'last active row
Dim element as Range
Dim joincheck as Range
' it doesn't matter if we loop through range1 and search in range2 or vice versa.
' because the element needs to be in both. However for practical reasons, since it's
' a lot easier to use Offset() to refer to price of the element,
' we'll loop through range2 and search in range1
For Each element in range2' loop through all range1 cells
Set joincheck = range1.Find(element, lookIn:=xlValues)
If Not joincheck is Nothing Then ' if found in range1
lr = ws.Cells(Rows.Count, "F").End(xlUp).Row ' get lr
ws.Range("F" & lr + 1) = element ' product name
ws.Range("G" & lr + 1) = element.Offset(0, 1) ' price
End If
' otherwise Find will return Nothing if not found and we can carry on
Next element
End Sub
这应该在调用时模拟INNER JOIN()
操作的预期结果。