模拟FULL OUTER JOIN: UNION of LEFT+RIGHT JOIN vs cross join的性能
Simulating FULL OUTER JOIN: Performance of UNION of LEFT+RIGHT JOIN vs cross join
Access / Jet 数据库引擎不支持 FULL OUTER JOIN
s:
SELECT Table1.*, Table2.*
FROM Table1
FULL OUTER JOIN Table2 ON Table1.JoinField = Table2.JoinField
通常推荐的替代方法是 UNION
LEFT
和 RIGH JOIN
的结果;以下内容的一些变化:
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 OUTER JOIN
。它是一个内部联接,也将 NULL 匹配到所有记录。
在 CROSS JOIN
中,一个 table 中的行总是与另一个 table 中的行匹配,而在 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)
(在链接示例中,您可以看到它的实际效果)
由于我使用的是 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
但是如果你只合并你会得到相同的结果。
Access / Jet 数据库引擎不支持 FULL OUTER JOIN
s:
SELECT Table1.*, Table2.*
FROM Table1
FULL OUTER JOIN Table2 ON Table1.JoinField = Table2.JoinField
通常推荐的替代方法是 UNION
LEFT
和 RIGH JOIN
的结果;以下内容的一些变化:
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 OUTER JOIN
。它是一个内部联接,也将 NULL 匹配到所有记录。
在 CROSS JOIN
中,一个 table 中的行总是与另一个 table 中的行匹配,而在 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)
(在链接示例中,您可以看到它的实际效果)
由于我使用的是 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
但是如果你只合并你会得到相同的结果。