1

これらの3つのテーブルを想像してみてください。

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

サブクエリ/サブセレクトを実行せずに持っていないすべてのユーザーを選択することは可能ですLoginInfos(私はこれをDBと照合せずに作成しました):

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 (!)

言い換えると、「少なくとも1つの要素が不明であり、5である可能性があるため、セットに含まれて
いるかどうかはわかりません。」5条項は関連するだけ
なので(テストにも合格もしません)、まったく影響しません。WHERETRUENULLFALSEWHERE id IN (...)

しかし、それは影響します

WHERE id NOT IN (...)
この式は、右側のセットにが含まれるとすぐに修飾されません。 おそらく意図したとおりではありませんか?NULL


解決

要件は

LoginInfosを持たないすべてのユーザーを選択します

これには、テーブルに行がないユーザーも含まれる可能性がありますlogin。したがって、LEFT JOIN2回必要です。また、1人のユーザーがに複数の行を持つことができるかどうかは定義されていないため、または: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

これはすべての不測の事態をカバーします。あなたができる...

  • ユーザーごとに最大1回のログインDISTINCTが可能な場合は削除します。
  • すべてのユーザーに対して少なくとも1つの行がある場合は、最初LEFT JOINの行をに置き換えます。JOINlogin

この代替方法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
   )
于 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 に答える