【问题标题】:Simulating FULL OUTER JOIN: Performance of UNION of LEFT+RIGHT JOIN vs cross join模拟 FULL OUTER JOIN:LEFT+RIGHT JOIN 与交叉连接的 UNION 性能
【发布时间】:2018-10-21 12:13:38
【问题描述】:

Access / Jet 数据库引擎不支持FULL OUTER JOINs:

SELECT Table1.*, Table2.*
FROM Table1
FULL OUTER JOIN Table2 ON Table1.JoinField = Table2.JoinField

通常推荐的替代方法是UNIONLEFTRIGH JOINs 的结果;以下内容的一些变化:

SELECT Table1.*, Table2.*
FROM Table1
LEFT JOIN Table2 ON Table1.JoinField = Table2.JoinField

UNION ALL 
SELECT Table1.*, Table2.*
FROM Table1
RIGHT JOIN Table2 ON Table1.JoinField = Table2.JoinField
WHERE Table1.JoinField IS NULL

但是,是否也可以使用交叉连接?

SELECT Table1.*, Table2.*
FROM Table1, Table2
WHERE Table1.JoinField = Table2.JoinField
    OR Table1.JoinField IS NULL
    OR Table2.JoinField IS NULL

以这种方式使用交叉连接有任何性能损失或其他缺点吗?

【问题讨论】:

  • 我建议创建两个表,用虚拟数据填充它们,并将 full join 结果与您的 , 替代结果进行比较。
  • @hvd 我觉得自己没有足够的能力创建具有足够相关的虚拟数据和结构的表来进行这样的实验。
  • 我不认为 UNION 选项中的 where 子句是必要的......事实上,我觉得它可能会阻止你获得一些所需的结果......我错过了什么吗?
  • @IsaacReefman 如果使用UNION ALL,那么INNER JOINed 记录会出现两次。一种替代方法是使用UNION,但前提是没有其他重复记录。
  • 我相信所有的结果都是完全不同的。最后一个 sql 只会给你常见的行。第 2 个 sql 和第 1 个 sql 也会给出 dirr 结果。

标签: sql ms-access outer-join jet


【解决方案1】:

您的交叉连接根本不是FULL OUTER JOIN。这是一个内部连接,它也将 NULL 匹配到所有记录。

CROSS JOIN 中,一个表中的行总是与另一个表中的行匹配,而在FULL OUTER JOIN 中,有些行不匹配。

为了说明,我创建了一个小的sample(T-SQL,但这不相关)。可以看到返回了一个不相等的行。

但是,如果没有 Null 值,您可以使用 CROSS JOIN 来模拟 FULL OUTER JOIN,方法是附加 Null 行,使用 NOT EXISTS 和其他一些技巧。但是,您会发现这是一个非常复杂的解决方案,通常首选普通的UNION

SELECT *
FROM (SELECT * FROM #Table1 UNION ALL SELECT Null, Null) t1, (SELECT * FROM #Table2 UNION ALL SELECT Null, Null) t2
WHERE (t1.JoinField = t2.JoinField
OR (NOT EXISTS(SELECT 1 FROM #Table2 WHERE #Table2.JoinField = t1.JoinField) AND t1.JoinField Is Not Null AND t2.JoinField IS NULL)
OR (NOT EXISTS(SELECT 1 FROM #Table1 WHERE #Table1.JoinField = t2.JoinField) AND t2.JoinField Is Not Null AND t1.JoinField IS NULL))
AND (t1.JoinField Is Not Null Or t2.JoinField Is Not Null) 

(在链接的示例中,您可以看到它的实际效果)

【讨论】:

    【解决方案2】:

    由于我使用的是 Redshift,可能存在语法差异。

    With a as
    (
    Select 1 id union all
    Select 2 union all
    Select 3 
    )
    , b as 
    (
    Select 2 d union all
    Select 4 union all
    Select 5 
    )
    Select a.*,b.* 
    From a full join b on id=d
    

    输出是

    id  d
    1   NULL
    2   2
    3   NULL
    NULL    4
    NULL    5
    

    如果你运行

    Select a.*,b.* 
    from a 
    left join b on id=d 
    union all
    Select  a.*,b.* 
    from b 
    left join a on d=id
    

    你得到

    id  d
    1   NULL
    2   2
    3   NULL
    2   2
    NULL    4
    NULL    5
    

    但如果你只联合你会得到相同的结果。

    【讨论】:

    • 或者使用'WHERE'子句从UNION ALLas in my question的第二个子查询中显式排除INNER JOIN记录。此外,使用 UNION 而不是 UNION ALL 假定没有其他重复结果。
    猜你喜欢
    • 2012-02-27
    • 2013-03-10
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 2020-01-10
    相关资源
    最近更新 更多