使用NOT IN()的SQL连接不起作用

时间:2017-06-14 15:48:06

标签: mysql sql database join

我有两个包含相同密钥p_id的表:

test1                       test2
+-------------+             +----------------------+
| p_id | name |             | o_id | name  |  p_id |
+-------------+             +----------------------+
|  1   | Paul |             |  1   | London |   1  |
|  2   | Marc |             |  2   | Paris  |   1  |        
+-------------+             +----------------------+

现在我想从test1获取与test2无关的所有条目。 在上面的示例中,我抽象了我的表,因此RIGHT JOIN是不可能的(实际上我必须加入4个表)。

SELECT a.*,b.*
FROM test1 a
LEFT JOIN test2 b
ON a.p_id=b.p_id
WHERE b.p_id NOT IN(SELECT DISTINCT p_id FROM test2);

我希望有一行p_id=2。但是我得到一个空洞的结果。 当我将代码更改为:

SELECT a.*,b.*
FROM test1 a
LEFT JOIN test2 b
ON a.p_id=b.p_id
WHERE a.p_id NOT IN(SELECT DISTINCT p_id FROM test2);

然后它工作正常。但为什么?我认为首先处理LEFT JOIN(结果为1行),之后处理WHEREp_id中未找到test2,因此b.p_id为{ {1}} - null不在subselect中 - 因此结果仍为1行。

有人可以解释一下这种行为吗?

4 个答案:

答案 0 :(得分:2)

它与比较中如何处理NULL有关。

要测试/查看,您可以运行简单的查询,例如:

SELECT 1 来自双重 WHERE NULL = NULL;

SELECT 1 来自双重 WHERE NULL NOT IN(1,2,3);

既不返回一行,因为两个条件都返回NULL,这是"不是真的"。

答案 1 :(得分:2)

正如Uueerdo所说,这是一个NULL比较问题。但除此之外,你应该真的使用反连接:

SELECT a.*,b.*
FROM test1 a
LEFT JOIN test2 b
ON a.p_id=b.p_id
WHERE b.p_id IS NULL;

它更干净,效率更高。

答案 2 :(得分:1)

NOT IN没有错,因为您正在过滤Where子句中的右表,它会隐式转换为INNER JOIN

如果没有Where子句,结果就会像这样

+------+------+--------+--------+--------+
| p_id | name |  o_id  |  name  |  p_id  |
+------+------+--------+--------+--------+
|    1 | Paul | 1      | London | 1      |
|    1 | Paul | 2      | Paris  | 1      |
|    2 | Marc | (null) | (null) | (null) |
+------+------+--------+--------+--------+

如果您要应用过滤器,请执行此操作

WHERE b.p_id NOT IN(SELECT DISTINCT p_id FROM test2);

子查询返回1,它出现在上面结果的最后一列中。所以你没有得到任何结果。

如果您想知道为什么没有返回NULL的最后一条记录,因为它不是1。这是因为NULL无法使用=INNOT IN等进行比较。我们需要使用IS运算符来检查NULL < / p>

执行此操作的正确方法是使用NOT EXISTS。同时处理NULL个值

select * 
from test1 a
Where Not Exists (select 1 from test2 b Where a.p_id = b.p_id)

答案 3 :(得分:0)

通常,首先执行WHERE,然后执行JOIN。此外,当你使用LEFT JOIN时,LEFT表包含所有内容,所以你不应该期望在JOIN之后有一行p_id = 2,正如你所说的那样。