简体   繁体   中英

Select records from a table which are not in other table

I have two tables in my database :

Table 1 (BonInterne) :

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

Table 2 (LigneBonInterne) :

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

I want to get all records from table 1 which have a num isn't in the second table, and this is the scipt I tried :

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

But MySQL returned an empty result set.

He should return as following :

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

What I have to change in my query to get that table ??

SQL 101

SELECT x.* 
  FROM x
  LEFT
  JOIN y
    ON y.thing = x.thing
 WHERE y.thing IS NULL;
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

One explanation for why your original query did not work is if the LigneBonInterne table contains null values for numBon column. The In function translates into a series of Or statements (eg Foo In(A,B,C) equates to Foo = A Or Foo = B Or Foo = C . In the case of Foo Not In(A,B,C) we get Foo <> A And Foo <> B And Foo <> C .). Thus, if one of the values is null we'll get a comparison to null and that will return false (technically it returns Unknown).

This SQL Fiddle example shows your original query but note that I added a null value for numBon and do not get results. Take that value out, and we do.

If indeed you have nulls in the LigneBonInterne , then the above solution will work. Another choice is to use the In function but filter out nulls in your subquery

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

Another choice is to use Exists instead of In :

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

When using Exists , the Select clause is entirely ignored. Some people use Select * , some people use Select Null , some use Select 1 . It should not matter; all that matters is whether the rest of query returns rows or not. This type of query is called a correlated subquery because there is a reference in the inner query to a column the outer query ( L1.numBon = B.num ).

So, which form should you use? In this case, clarity of intent can be achieved by any of the three forms. However, database products vary in their ability to efficiently handle correlated subqueries. In the case of MySQL, it will probably perform the best with a Left Join, then an In function and last an Exists function.

Your query is very close, you just need to include a where clause to filter for those values that are not null:

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

See SQL Fiddle with Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM