简体   繁体   English

模拟完全外部联接:LEFT + RIGHT JOIN的UNION与交叉联接的性能

[英]Simulating FULL OUTER JOIN: Performance of UNION of LEFT+RIGHT JOIN vs cross join

The Access / Jet database engine doesn't support FULL OUTER JOIN s: Access / Jet数据库引擎不支持FULL OUTER JOIN

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

The commonly recommended alternative is to UNION the results of the LEFT and RIGH JOIN s; 通常推荐的替代方法是UNION LEFTRIGH JOIN的结果。 some variation on the following: 在以下方面有一些变化:

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

However, isn't it also possible to use a cross join? 但是,是否也可以使用交叉联接?

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

Are there any performance penalties or other downsides to using a cross join in this way? 以这种方式使用交叉联接是否会对性能造成任何不利影响?

Your cross join isn't a FULL OUTER JOIN at all. 您的交叉FULL OUTER JOIN根本不是FULL OUTER JOIN It's an inner join that also matches NULL to all records. 这是一个内部联接,也将NULL匹配到所有记录。

In a CROSS JOIN , rows from one table are always matched with rows from another table, while in a FULL OUTER JOIN , there are rows that are matched to nothing. CROSS JOIN ,一个表中的行总是与另一表中的行匹配,而在FULL OUTER JOIN ,有任何行都不匹配。

To illustrate, I created a small sample (T-SQL, but that's not relevant). 为了说明,我创建了一个小样本 (T-SQL,但这无关紧要)。 You can see that an inequal row is returned. 您可以看到返回了不相等的行。

You can, however, use a CROSS JOIN to emulate a FULL OUTER JOIN , if there are no Null values, by appending a Null row, using NOT EXISTS , and some more tricks. 但是,如果没有Null值,则可以使用CROSS JOIN来模拟FULL OUTER JOIN ,方法是通过附加Null行,使用NOT EXISTS以及其他一些技巧来模拟。 You'll see, however, that this is a very elaborate solution, and the normal UNION is usually preferred: 但是,您会看到这是一个非常复杂的解决方案,通常首选普通的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) 

(In the linked sample, you can see it in action) (在链接的示例中,您可以看到它的运行情况)

As I am using Redshift there may be syntax difference. 当我使用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

Output is 输出是

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

If you run 如果你跑

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

You get 你得到

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

But if you union only you get same result. 但是,如果仅合并,您将得到相同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM