开发者

SQL Server 2000 strange subquery problem

开发者 https://www.devze.com 2023-02-21 14:19 出处:网络
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.

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.IDUse开发者_高级运维r = 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 WHERE condition 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), or
2) use NOT EXISTS, e.g.:

SELECT DISTINCT IDRecord 
  FROM Users u
 WHERE NOT EXISTS (
         SELECT 1 
           FROM Permissions p 
          WHERE p.IDUser = u.IDRecord
       );

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...

...
WHERE a_column <> 'some value';

Suddenly rows where a_column is NULL disappear from your results.
To get them back you can do this:

...
WHERE (a_column <> 'some value' OR a_column IS NULL);
0

精彩评论

暂无评论...
验证码 换一张
取 消