Excel中是否有INNER JOIN?

时间:2018-08-17 15:52:23

标签: excel vba excel-vba excel-formula inner-join

我希望基于匹配的列值在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

我已经尝试过VLOOKUPMATCH,但是无法模拟INNER JOIN中存在的SQL函数。希望StackOverflow社区可以提供一些帮助:)

4 个答案:

答案 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),"")

enter image description here


这可以用一个公式完成:

=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所指出的那样,这非常容易,您可以在将两个表都存储在内存中之后使用合并查询功能内部连接两个表。

  1. 将两个表都设置为Excel表
  2. 在表格中选择一个单元格,然后选择powerquery标签(2013年); “获取和转换数据”选项卡Excel 2016>从表中(新查询)
  3. 这将加载表并显示查询编辑器。转到首页标签,然后选择关闭并加载到

Close

  1. 选择仅关闭并加载连接

connection only

为另一个表重复步骤2-4,这样两个表都在内存中。

both tables

  1. 新查询>合并查询>合并查询

merge

  1. 在弹出的窗口中选择两个表,确保突出显示两个表中的“股票行情指示器”列,并将联接类型设置为内部联接

inner join

  1. 展开“表格”列上的<>箭头,然后取消选中报价栏(删除重复的列)

duplicate column

expanded table

  1. 根据需要重命名列。关闭并将结果加载到工作表中

load

  1. 查看结果

result

答案 3 :(得分:1)

好吧,这是Catch 22 ...因为它可以同时进行,而且不能同时完成


在此之下我的意思是,Excel主要用于静态数据。尽管结果可能会根据公式而有所不同,但为了检查值,需要在某个地方指定该值。

内部联接是一种基本上需要两个实体并从中创建一个新实体的操作,如下所示:

enter image description here

正如@ScottCraner正确指出的那样,这不是Excel要做的。这样我们就有3个选择(或者至少我能想到很多)。

重要的是要指出我们甚至没有能力做适当的INNER JOIN(),但我们至少可以制造一种错觉-基本上是对它应该做什么的模仿


  1. 手动方式-我写了一个答案,但@ScottCraner击败了我,我敢说这很优雅,所以直接参考他的话

  2. 方式-我将在下面回答

  3. 通过 -我对自己不太熟悉,因此您必须进行自己的研究,也许其他人会回答。


方式:

  

假设我们有以下数据:

     

enter image description here

如果我们要描述INNER JOIN()如何以算法的方式工作,它将看起来像这样。

  1. 取范围(数据数组)a
  2. 取范围(数据数组)b
  3. 比较数据并返回新的结果数组r = a ∩ b

    3.1表达式a ∩ b可以按以下方式“以编程方式”编写:

    • For a中的每个元素:
    • ifexists中的b
    • pushr结果数组
    • 否则转到Next元素
  4. 返回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()操作的预期结果。