There’s a strange behaviour that is drive me crazy.
I’ve a table of users and a table of permissions in an old SQL Server 2000 database.
This database is a mess, many tables have no PK and there are no relations between the tables… but I couldn’t fix it (and honestly I don’t think this is related to the problem I have).
Users:
IDRecord -> PK money
-- other fields
Permissions:
IDRecord -> money (is not a PK)
IDUser -> money (refers to Users.IDRecord WITHOUT FK)
Function -> varchar
-- other fields
I want to get the User’s ids of the users without any permission.
My first approach was to write something as:
select distinct IDRecord
from Users
where IDRecord not in (
select IDUser from Permissions
)
That returns me no rows.
But I KNOW there are users without permissions, so I write a second query:
select distinct U.IDRecord
from Users U
left join Permissions P
on P.IDUser = U.IDRecord
where P.IDRecord is null
that correctly returns the users without permissions.
So, where’s the problem?
Why the first doesn’t work?
This is expected behavior.
It is expected because SQL has three-valued logic.
In other words: for those users who have no permissions, there is no result (NULL) returned by your subquery.
Your
WHEREcondition is not satisfied in those cases because a value can never equal nor not equal NULL.Alternatives:
1) use a
LEFT JOIN(as you have done), or2) use
NOT EXISTS, e.g.:Edit: More detail on how 3VL can bite you if you’re not careful:
A possibly counter-intuitive result occurs if you do something like this…
Suddenly rows where
a_columnis NULL disappear from your results.To get them back you can do this: