2017-05-26 90 views
-1

我有时会与左连接和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' 
+0

这个问题是关于运算符优先级 - 它无关,与加入“左外”或以其他方式。 –

+0

也是,你不能在oracle中使用'as'作为表别名。 –

回答

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

在第二种情况下,先在支架上的表达式进行求值,然后将下面的“:像这样 - ,其中COL4 =“R”和COL5 =“DR”只从表-B加入的行AND“操作符被应用。 !所以结果,如果上述托架表达相与B.col4 =“R”,然后将其相与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' 

在第一种情况下,将其评价像以下:

(B.col1 IS NULL) OR (B.col2 IS NULL) OR (B.col3 IS NULL AND B.col4= 'R' AND B.col5 != 'DR') 
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运算,那么你应该使用括号。

+0

(B.col4 ='R'AND B.col5!='DR')是完全独立的条件。 –

+0

据我所知,我已经解释了两个查询之间的行为差​​异。 –

+0

您是否编辑过您的早期回复?只是问问。我没有注意到最近的声明。 –

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为空,则意味着table_b行不是连接的一部分,所以col4和col5也将为null。

相反,我认为你的意思是使and b.col4 = 'R' and b.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          
+0

感谢你和所有在这里回复的人。经过密切观察,我明白了我错在哪里。 –

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.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.col3NULL(当有在LEFT OUTER JOIN匹配)或者和B.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')