从表中选择不在其他表中的记录

时间:2013-06-07 15:48:00

标签: mysql

我的数据库中有两个表:

表1(BonInterne):

+---------+
|   num   | 
+---------+
|1        |
+---------+
|2        |
+---------+
|3        |
+---------+
|4        |
+---------+

表2(LigneBonInterne):

+---------+-----------+
|numOrdre |numBon     |
+---------+-----------+
|20       |1          +
+---------+-----------+
|21       |2          |
+---------+-----------+
|22       |NULL       +
+---------+-----------+
|23       |2          |
+---------+-----------+
|24       |1          +
+---------+-----------+
|25       |2          |
+---------+-----------+
|26       |NULL       +
+---------+-----------+
|27       |1          |
+---------+-----------+

我想从表1中获取所有记录,其中num不在第二个表中,这是我尝试的scipt:

SELECT * FROM BonInterne WHERE num NOT IN (SELECT numBon FROM LigneBonInterne)

但是MySQL返回了一个空的结果集。

他应该返回如下:

+---------+
|   num   | 
+---------+
|3        |
+---------+
|4        |
+---------+

我需要在查询中更改以获取该表吗?

3 个答案:

答案 0 :(得分:2)

SQL 101

SELECT x.* 
  FROM x
  LEFT
  JOIN y
    ON y.thing = x.thing
 WHERE y.thing IS NULL;

答案 1 :(得分:2)

Select B.num
From BonInterne As B
    Left Join LigneBonInterne As L
        On L.numBon = B.num
Where L.numBon Is Null  

SQL Fiddle version

Visual Explanation of Joins

原始查询无效的原因之一是LigneBonInterne表包含numBon列的空值。 In函数转换为一系列Or语句(例如Foo In(A,B,C)等同于Foo = A Or Foo = B Or Foo = C。对于Foo Not In(A,B,C),我们得到Foo <> A And Foo <> B And Foo <> C。 )。因此,如果其中一个值为null,我们将得到null的比较,并返回false(技术上它返回Unknown)。

SQL Fiddle example会显示您的原始查询,但请注意我为numBon添加了空值,但未获得结果。拿出那个价值,我们就这样做了。

如果LigneBonInterne中确实存在空值,则上述解决方案将起作用。另一种选择是使用In函数,但过滤掉子查询中的空值

Select B.num
From BonInterne As B
Where Not In    (
                Select L1.numBon
                From LigneBonInterne As L1
                Where L1.numBon Is Not Null
                )

另一种选择是使用Exists代替In

Select B.num
From BonInterne As B
Where Not Exists    (
                    Select 1
                    From LigneBonInterne As L1
                    Where L1.numBon = B.num
                    )

使用Exists时,Select子句完全被忽略。有些人使用Select *,有些人使用Select Null,有些人使用Select 1。没关系;重要的是查询的其余部分是否返回行。这种类型的查询称为相关子查询,因为在内部查询中有一个引用外部查询(L1.numBon = B.num)的列。

那么,你应该使用哪种形式?在这种情况下,可以通过三种形式中的任何一种来实现意图的清晰。但是,数据库产品在有效处理相关子查询的能力方面各不相同。在MySQL的情况下,它可能会通过左连接,然后是In函数和最后的Exists函数执行最佳。

答案 2 :(得分:2)

您的查询非常接近,您只需要包含一个where子句来过滤那些非空的值:

SELECT num
FROM BonInterne 
WHERE num NOT IN (SELECT numBon 
                  FROM LigneBonInterne
                  where numBon is not null);

请参阅SQL Fiddle with Demo