【问题标题】:How do accomplish this join in SQL?如何在 SQL 中完成这种连接?
【发布时间】:2013-07-16 21:59:05
【问题描述】:

如何在 SQL 中完成这种连接?

表 1

+----+-----------+-----------+---------+
| ID | FILTER1   | FILTER2   | DATA1   |
| 1  | filter1-A | filter2-A | data1-A |
| 2  | filter1-B | filter2-B | data1-B |
+----+-----------+-----------+---------+

表2

+----+-----------+-----------+---------+
| ID | FILTER1   | FILTER2   | DATA1   |
| 1  | filter1-B | filter2-B | data2-B |
| 2  | filter1-C | filter2-C | data2-C |
+----+-----------+-----------+---------+

结果

+------------+-----------+---------+---------+
| FILTER1    | FILTER2   | DATA1   | DATA2   | 
| filter1-A  | filter2-A | data1-A | NULL    | 
| filter1-B  | filter2-B | data1-B | data2-B | 
| filter1-C  | filter2-C | NULL    | data2-C | 
+------------+-----------+---------+---------+

【问题讨论】:

    标签: sql sql-server join


    【解决方案1】:
    SELECT
      COALESCE(TABLE1.filter_1, TABLE2.filter_1)   AS filter_1,
      COALESCE(TABLE1.filter_1, TABLE2.filter_2)   AS filter_2,
      TABLE1.data1                                 AS data_1,
      TABLE2.data2                                 AS data_2
    FROM
      TABLE1
    FULL OUTER JOIN
      TABLE2
        ON  TABLE1.filter_1 = TABLE2.filter_1
        AND TABLE1.filter_2 = TABLE2.filter_2
    

    FULL OUTER JOIN 保留每个表中的每条记录,无论其他表中是否存在匹配项。

    COALESCE()(有些使用ISNULL()然后可用于扫描缺失/NULL 值以查找第一个非 NULL 值。

    【讨论】:

    • 请在这里验证我的逻辑:如果我知道 TABLE1 包含所有过滤器组合,我可以使用左连接而不使用 COALESCE,我的查询会快得多。
    • @MattAlexander - COALESCE 几乎不会影响性能。标量函数,即使在大量输出记录上执行时,与连接本身相比也几乎总是微不足道的。但是,是的,在您的新示例中,您可以使用 LEFT JOIN,这可能会带来性能优势,具体取决于索引等。
    【解决方案2】:

    这称为全外连接。

    SELECT 
      ISNULL(T1.FILTER1, T2.FILTER1) AS FILTER_1, 
      ISNULL(T1.FILTER2, T2.FILTER2) AS FILTER_2,
      T1.DATA1 AS DATA_1, 
      T2.DATA1 AS DATA_2
    FROM TABLE1 T1
    FULL OUTER JOIN TABLE2 T2
      ON T1.FILTER1 = T2.FILTER1
     AND T1.FILTER2 = T2.FILTER2
    

    【讨论】:

    • 是的,我忘记将 TABLE1.FILTER1 和 TABLE2.FILTER1 合并为一列。我太快回答并专注于“加入”部分,让我编辑我的答案。
    • ISNULL 不是非标准的 SQL 行为吗?
    • @user1759572 - OP 声明 SQL-SERVER 和 ISNULL 在那里完全正常。
    • @user1759572 我认为这是非标准的,我不能 100% 确定。但是这个问题被标记为 sql-server 并且它比(相当长的)COALESCE 更短,所以......
    【解决方案3】:
    SELECT G.FILTER1, G.FILTER2, T1.DATA1, T2.DATA1 as DATA2 FROM
        (SELECT FILTER1, FILTER2
        FROM TABLE1
      UNION
        SELECT FILTER1, FILTER2
        FROM TABLE2
      GROUP BY FILTER1, FILTER2) as G
    LEFT JOIN TABLE1 as T1 ON T1.FILTER1 = G.FILTER1 AND T1.FILTER2 = G.FILTER2
    LEFT JOIN TABLE2 as T2 ON T2.FILTER1 = G.FILTER1 AND T2.FILTER2 = G.FILTER2
    

    【讨论】:

    • 为什么这比 FULL OUTER JOIN 更好?这似乎是阅读次数的两倍......
    • 没有偏好,只是另一种方式。在性能方面,它的性能不如 FULL OUTER JOIN。
    【解决方案4】:

    您也可以使用 union allgroup by 执行此操作——假设两个表在表中都没有重复:

    select filter_1, filter_2, max(data_1) as data_1, max(data_2) as data_2
    from ((select filter_1, filter_2, data_1, NULL as data_2
           from table1
          ) union all
          (select filter_1, filter_2, NULL, data_2
           from table2
          )
         ) t
    group by filter_1, filter_2;
    

    我提供这个作为替代方案。一方面,有趣的是(对我而言)union all/group by 的行为与full outer join 相同。更重要的是,如果你开始添加更多的表,那么full outer join 的方法就会变得很麻烦。将此方法扩展到更多表很容易。

    【讨论】:

    • 您不需要 UNION 中的第一个 SELECT 来将 NULL 显式转换为正确的数据类型吗?如果不是,SQL Server 使用什么规则来确定以 NULL 初始化的字段的数据类型?
    猜你喜欢
    • 1970-01-01
    • 2023-01-17
    • 2023-03-07
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 2012-03-19
    相关资源
    最近更新 更多