左外连接 - 有什么区别?

时间:2017-05-26 13:36:48

标签: oracle join

我有时会对LEFT JOINS和OR感到困惑。

在下面的两个代码示例中,只有一个区别。一个样本的WHERE子句中有一个括号,其他样本中没有括号。

显然,我得到了不同的结果。我想了解发生了什么。

感谢。

SELECT FROM TABLE_A as A
LEFT OUTER JOIN TABLE_B  as B
      ON 
        A.col1 = B.col1 AND
        A.col2 = B.col2 AND
        A.col3 = B.col3
      WHERE
        B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL AND
        B.col4= 'R' AND
        B.col5 != 'DR'


SELECT FROM TABLE_A as A
LEFT OUTER JOIN TABLE_B  as B
      ON 
        A.col1 = B.col1 AND
        A.col2 = B.col2 AND
        A.col3 = B.col3
      WHERE
        (B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL) AND
        B.col4= 'R' AND
        B.col5 != 'DR'

4 个答案:

答案 0 :(得分:1)

AND运算符的优先级高于OR,因此您的第一个WHERE子句可以这样写:

WHERE
    B.col1 IS NULL OR B.col2 IS NULL OR (B.col3 IS NULL AND
    B.col4= 'R' AND
    B.col5 != 'DR')

但如果您的WHERE条款的第二个版本是任何证据,那么这可能不是您的意图。如果要检查三列中的任何一列NULL与其他两个条件进行AND运算,那么您应该使用括号。

答案 1 :(得分:1)

我认为你对左连接以及AND / OR运算符优先级感到非常困惑。

在您的第一个查询中,订单从左向右应用,首先应用ANDS。

这意味着您的第一个查询相当于:

SELECT *
FROM   table_a a
       LEFT OUTER JOIN table_b b ON (a.col1 = b.col1
                                     AND a.col2 = b.col2
                                     AND a.col3 = b.col3)
WHERE b.col1 IS NULL
OR    b.col2 IS NULL
OR    (b.col3 IS NULL
       AND b.col4 = 'R'
       AND b.col5 != 'DR');

但是,您的第二个查询是在三个连接条件中的任何一个中检查空值(这些条件可能全为空,或者全部不为空,因为您没有在连接条件中为空值提供服务)以及检查其余两列中是否存在值。这没有意义 - 如果col1,col2和col3为null,则表示table_b行不是连接的一部分,因此col4和col5也将为null。

相反,我认为你打算做的是使左外连接条件的and b.col4 = 'R' and b.col5 != 'DR'部分 - 即。只加入table_b中的行,其中col4 ='R'和col5!='DR' - 就像这样:

WITH table_a AS (SELECT 1 col1, 1 col2, 1 col3 FROM dual UNION ALL
                 SELECT 2 col1, 2 col2, 2 col3 FROM dual UNION ALL
                 SELECT 3 col1, 3 col2, 3 col3 FROM dual),
     table_b AS (SELECT 1 col1, 1 col2, 1 col3, 'R' col4, 'DP' col5 FROM dual UNION ALL
                 SELECT 2 col1, 2 col2, 2 col3, 'R' col4, 'DR' col5 FROM dual)
SELECT *
FROM   table_a a
       LEFT OUTER JOIN table_b b ON (a.col1 = b.col1
                                     AND a.col2 = b.col2
                                     AND a.col3 = b.col3
                                     AND b.col4 = 'R'
                                     AND b.col5 != 'DR');

      COL1       COL2       COL3       COL1       COL2       COL3 COL4 COL5
---------- ---------- ---------- ---------- ---------- ---------- ---- ----
         1          1          1          1          1          1 R    DP
         2          2          2                                       
         3          3          3                                       

答案 2 :(得分:1)

(B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL)

在第二种情况下,首先评估括号中的表达式,然后应用以下“AND”运算符。因此,如果括号表达式上方的结果与B.col4 ='R'进行AND运算,然后与B.col5进行AND运算!='DR'

B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL AND
    B.col4= 'R' AND
    B.col5 != 'DR'

在第一种情况下,评估如下:

(B.col1 IS NULL) OR (B.col2 IS NULL) OR (B.col3 IS NULL AND B.col4= 'R' AND B.col5 != 'DR')

答案 3 :(得分:0)

您的第二个查询不是LEFT OUTER JOIN

SELECT *
FROM   TABLE_A A
       LEFT OUTER JOIN TABLE_B B
       ON (   A.col1 = B.col1
          AND A.col2 = B.col2
          AND A.col3 = B.col3 )
WHERE  ( B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL )
AND    B.col4= 'R'
AND    B.col5 != 'DR'

WHERE子句只接受B.col4B.col5NOT NULL的行,这种情况只会在表格连接时出现,这意味着加入条件实际上是INNER JOIN

但是,条件( B.col1 IS NULL OR B.col2 IS NULL OR B.col3 IS NULL )( A.col1 = B.col1 AND A.col2 = B.col2 AND A.col3 = B.col3 )永远无法同时满足,因为NULL值不能等于任何其他值(包括另一个NULL)。所以查询永远不会返回任何行。

第一个查询是:

SELECT *
FROM   TABLE_A A
       LEFT OUTER JOIN TABLE_B B
       ON (   A.col1 = B.col1
          AND A.col2 = B.col2
          AND A.col3 = B.col3 )
WHERE  B.col1 IS NULL
OR     B.col2 IS NULL
OR     ( B.col3 IS NULL AND B.col4= 'R' AND B.col5 != 'DR' )

这将在B.col1 IS NULL OR B.col2 IS NULL时返回行,但在( B.col3 IS NULL AND B.col4= 'R' AND B.col5 != 'DR' )上永远不会匹配,因为加入条件将强制执行B.col3不是NULL(当匹配时LEFT OUTER JOIN)或B.col4B.col5都是NULL(当LEFT OUTER JOIN中没有匹配项时)。

你可能实际想要实现的目标(虽然你的问题不清楚)是:

SELECT *
FROM   TABLE_A A
       LEFT OUTER JOIN TABLE_B B
       ON (   A.col1 = B.col1
          AND A.col2 = B.col2
          AND A.col3 = B.col3
          AND          B.col4 = 'R'
          AND          B.col5 != 'DR' )