Кажется, что эти запросы делают одно и то же:
SELECT *
FROM users
WHERE id NOT IN (
SELECT user_id
FROM banned_users
);
Но если banned_users.user_id содержит хотя бы один NULL, запрос может вернуть ноль строк.
Надёжнее использовать NOT EXISTS:
SELECT u.*
FROM users AS u
WHERE NOT EXISTS (
SELECT 1
FROM banned_users AS b
WHERE b.user_id = u.id
);
Причина в трёхзначной логике SQL: сравнение с NULL даёт UNKNOWN, а не TRUE или FALSE.
Правило простое: если подзапрос потенциально возвращает NULL, вместо NOT IN почти всегда выбирайте NOT EXISTS.
