Reputation: 183
In an exam I was asked to retrieve the name of the transporters never having transported a container based in Rotterdam. The correct answer was
select Transporter.ID
from Transporter
where Transporter.ID not in (
select TransporterID
from Container
inner join Transportation on Container.ID = Transportation.ContainerID
where Container.City = 'Rotterdam')
and nevertheless the following was marked as a wrong answer:
select Transporter.ID
from Transporter
where Transporter.ID in (
select TransporterID
from Container
inner join Transportation on Container.ID = Transportation.ContainerID
where Container.City <> 'Rotterdam')
Why don't both statements lead to the same result? What is the practical difference between in ( ... where A <> B )
and not in ( ... where A = B )
?
[Note that Transportation
is in the center of the relational scheme, with all its prime attributs being foreign keys]
Upvotes: 0
Views: 58
Reputation: 6329
Besides what the other answers point out, take NULL
s into consideration:
If City
is NULL
both queries would treat the comparison as FALSE
in their WHERE
clause...
Upvotes: 1
Reputation: 15257
Let's build a simple table as example :
Container
TransporterID | City
1 | 'Rotterdam'
1 | 'Paris'
2 | 'Rotterdam'
And then this query
SELECT TransporterID
FROM Container
WHERE Container.City <> 'Rotterdam'
This will result 1 (the row with paris)
Then, WHERE Transporter.ID IN ( ...
statement will give wrong result (transporter 1 has been to 'Rotterdam')
Upvotes: 2
Reputation: 1271003
You version is answering a slightly different question: "What are the ids of transporters that have transported a container somewhere other than Rotterdam?".
As for the best answer, I would use not exists
(which is material) and table aliases (more stylistic):
select t.ID
from Transporter t
where not exists (select 1
from Container c join
Transportation tr
on c.ID = t.ContainerID
where tr.TransporterID = t.id and
c.City = 'Rotterdam'
);
NOT IN
does not behave the way most people expect when any row in the subquery returns NULL
(all rows are filtered out in that case). NOT EXISTS
has the expected behavior.
Upvotes: 0