Reputation: 583
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 ??
Upvotes: 3
Views: 121
Reputation: 64674
Select B.num
From BonInterne As B
Left Join LigneBonInterne As L
On L.numBon = B.num
Where L.numBon Is Null
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 (e.g. 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.
Upvotes: 2
Reputation: 247860
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);
Upvotes: 2
Reputation: 33945
SQL 101
SELECT x.*
FROM x
LEFT
JOIN y
ON y.thing = x.thing
WHERE y.thing IS NULL;
Upvotes: 2