sql - 可以在没有子查询的情况下进行此查询吗?

标签 sql postgresql null left-join sql-in

想象一下这 3 个表:

User             Login:            LoginInfo:
----             -----             -----
id:integer       id:integer        id:integer
name:string      user_id:integer   login_id:integer

是否可以在不执行子查询/子选择的情况下选择所有没有 LoginInfos 的用户(我写这个时没有对照数据库检查):

select id from users 
where id not in (
  select distinct(user_id) from logins 
  right join login_infos on logins.id = login_infos.login_id
)

我正在使用 Postgres 作为数据库。

最佳答案

为什么要使用 RIGHT JOIN

您可能会将 NULL 添加到子查询的结果中,这是 NOT IN 构造中的常见陷阱。

考虑这个简单的演示:

SELECT 5 NOT IN (VALUES (1), (2), (3))         --> TRUE
      ,5 NOT IN (VALUES (1), (2), (3), (NULL)) --> NULL (!)
      ,5     IN (VALUES (1), (2), (3))         --> FALSE
      ,5     IN (VALUES (1), (2), (3), (NULL)) --> NULL (!)

换句话说:
“我们不知道 5 是否在集合中,因为至少有一个元素是未知的,可能是 5。”
因为在 WHERE 子句中只有 TRUE 是相关的(NULLFALSE 都没有通过测试),它不会根本不会影响 WHERE id IN (...)

但是影响

WHERE id <b>NOT IN</b> (...)
只要右侧集合中存在 NULL,此表达式 never 就符合条件。
可能不是预期的那样?


解决方案

要求是

select all the Users that don't have LoginInfos

这可以包括在表 login 中也没有行的用户。因此,我们需要 LEFT JOIN 两次。由于未定义一个用户是否可以在 login 中有多行,因此我们还需要 DISTINCTGROUP BY:

SELECT DISTINCT u.*
FROM   users u
LEFT   JOIN login     l ON l.user_id  = u.id
LEFT   JOIN logininfo i ON i.login_id = l.id
WHERE  i.login_id IS NULL

这涵盖了所有可能发生的情况。你可以 ...

  • 如果每位用户至多一次登录,则移除DISTINCT
  • 如果每个用户在 login至少一行,则将第一个 LEFT JOIN 替换为 JOIN .

这个替代 NOT EXISTS使用子查询。
但无论每个用户在表 login 中有多少行,它都有效。而且它没有出现上述任何 NOT IN 问题:

SELECT u.*
FROM   users u
WHERE  NOT EXISTS (
   SELECT 1
   FROM   login     l
   JOIN   logininfo i ON i.login_id = l.id
   WHERE  l.user_id = u.id
   )

关于sql - 可以在没有子查询的情况下进行此查询吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15481203/

相关文章:

java - 数据库和 JPA 中不同的 PostgreSQL 序列 ID

postgresql - postgresql_select 在 macports 上的使用

java - 在返回 double java的方法中返回null

java - 无法弄清楚空指针异常

flutter - flutter 如何在获取快照的属性值时防止空值

mysql - SQL 比较日期

sql - 坚持用户选择的最佳方式是什么?

java - 结合 Java 和 SQL?

sql - postgres 查找特定邮政编码附近的邮政编码

sql - 窗口函数只能出现在 SELECT 或 ORDER BY 子句中