FULL OUTER JOIN 值条件
Posted
技术标签:
【中文标题】FULL OUTER JOIN 值条件【英文标题】:FULL OUTER JOIN value condition 【发布时间】:2012-02-13 00:21:45 【问题描述】:我需要为 FULL OUTER JOIN 添加值条件。
即我正在尝试这样做:
SELECT *
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5
但是这个脚本不起作用。实际上看起来条件(Table2.Field2 > 5)根本没有应用。
RIGHT OUTER JOIN 也出现了同样的问题,所以我认为原因是当存在 RIGHT 或 FULL 连接时,连接中的右表没有应用值条件。 为什么会这样?对这种行为有概念上的解释吗?
当然,主要问题是如何解决这个问题。
有没有办法在不使用子查询的情况下解决这个问题?
SELECT *
FROM Table1
FULL OUTER JOIN (SELECT * FROM Table2 WHERE Table2.Field2 > 5) AS t2 ON Table1.Field1 = t2.Field1
【问题讨论】:
【参考方案1】:这曾经让我感到困惑。现在我懂了! “on”之后的条件(在您的情况下:Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5 )告诉连接运算符两个表中的哪些行被连接。这意味着当且仅当 table1 中的 row1 和表中的 row2 满足 row1.field1 = row2.field2 和 row2.field2 > 5 时,才会连接 row1 和 row2。其余行未连接。
因此,在完全外连接中,结果集将是连接行、table1 中的非连接行和 table2 中的非连接行。 在右连接中,结果集将是来自 table2 的连接行和非连接行。 在任何一种情况下,表 2 中字段 2
这就是为什么“Table2.Field2 > 5”在左连接中正常工作,但在右连接或完全连接中却不是“正常”,但值条件确实在正确地工作。
【讨论】:
【参考方案2】:相当复杂,但没有子查询
SELECT Table1.*
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE COALESCE(Table2.Field2, 6) > 5
OR Table1.Field1 = Table2.Field1
测试脚本
;WITH Table1 AS (
SELECT * FROM (VALUES
(1, 1)
, (2, 2)
, (5, 5)
, (6, 6)
) AS Table1 (Field1, Field2)
)
, Table2 AS (
SELECT * FROM (VALUES
(1, 1)
, (3, 3)
, (4, 4)
, (5, 5)
, (7, 7)
) AS Table2 (Field1, Field2)
)
SELECT Table1.*
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
, CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE COALESCE(Table2.Field2, 6) > 5
OR Table1.Field1 = Table2.Field1
结果
Field1 Field2 Field1 Field2
1 1 NULL NULL
5 5 NULL NULL
NULL NULL 7 7
6 6 NULL NULL
1 1 NULL NULL
2 2 NULL NULL
【讨论】:
谢谢,但这仍然不是我想要的解决方案。虽然这种方法节省了查询结构(对我来说很重要,因为 SQL 语句是自动生成的),所以它比以前的解决方案更合适。仍然有很多额外的代码,所以也许我最终必须实现子查询解决方案。但是这个解决方案已经足够好了,所以我想我可以接受它作为答案。【参考方案3】:你想要的可能会被重新表述为:
SELECT *
FROM Table1
LEFT JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5
UNION ALL
SELECT *
FROM Table1
RIGHT JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE Table2.Field2 > 5
AND Table1.Field1 IS NULL
但是按照自己的建议使用子查询是 IMO 的最佳选择。
【讨论】:
感谢您的建议,但这对我来说不是一个好的解决方案。没错,它会起作用,但这比简单的子查询还要复杂。 @SergeyT:你不带子查询的问,我不带子查询的回答。您的解决方案可能是最好的选择。根据 RDBMS,您可以将其放入 WITH 子句中。以上是关于FULL OUTER JOIN 值条件的主要内容,如果未能解决你的问题,请参考以下文章
FULL OUTER JOIN 不能在没有连接两边的字段相等的条件下使用
如果没有条件与连接两侧的字段相等,则不能使用FULL OUTER JOIN
Redshift:将 FULL OUTER 替换为 CROSS JOIN
Oracle表与表之间的连接方式(内连接:inner join 外连接 全连接: full outer join左连接:left outer join 右连接:right outer join(代码