我有时会对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'
答案 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.col4
和B.col5
为NOT 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.col4
和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' )