1

想象一下这 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 作为数据库。

4

2 回答 2

2

为什么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中是相关的(既NULL没有通过测试也没有FALSE通过测试),所以它根本不会影响WHERE id IN (...)

但是会影响

WHERE id NOT IN (...)
只要右手集中有 a, 这个表达式就永远不合格。 可能不像预期的那样?NULL


解决方案

要求是

选择所有没有 LoginInfos 的用户

这可以包括在表中也没有行的用户login。因此,我们需要LEFT JOIN两次。而且由于没有定义一个用户是否可以在 中拥有多行login,我们还需要DISTINCTor GROUP 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只能登录一次,请删除。
  • 如果每个用户至少LEFT JOIN有一行,则替换第一个。JOINlogin

这种替代方案使用NOT EXISTS子查询。
但无论 table 中每个用户可以有多少行,它都有效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
   )
于 2013-03-18T17:32:16.920 回答
0
select distinct u.id
from
    user u
    inner join
    login l on u.id = l.user_id
    left join
    logininfo li on l.id = li.login_d
where li.id is null
于 2013-03-18T16:02:44.113 回答