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 值条件的主要内容,如果未能解决你的问题,请参考以下文章

带有OR条件的FULL OUTER JOIN

FULL OUTER JOIN 不能在没有连接两边的字段相等的条件下使用

如果没有条件与连接两侧的字段相等,则不能使用FULL OUTER JOIN

oracle的full outer join如何排除掉空值

Redshift:将 FULL OUTER 替换为 CROSS JOIN

Oracle表与表之间的连接方式(内连接:inner join 外连接 全连接: full outer join左连接:left outer join 右连接:right outer join(代码