他のテーブルに存在しない行を選択してください


172

2つのpostgresqlテーブルがあります。

table name     column names
-----------    ------------------------
login_log      ip | etc.
ip_location    ip | location | hostname | etc.

login_log行がないすべてのIPアドレスを取得したいip_location
このクエリを試しましたが、構文エラーがスローされます。

SELECT login_log.ip 
FROM login_log 
WHERE NOT EXIST (SELECT ip_location.ip
                 FROM ip_location
                 WHERE login_log.ip = ip_location.ip)
ERROR: syntax error at or near "SELECT"
LINE 3: WHERE NOT EXIST (SELECT ip_location.ip`

また、このクエリ(機能するように調整されたクエリ)が、この目的のために最もパフォーマンスの高いクエリであるかどうかも疑問に思っています。

回答:


386

このタスクには基本的に4つの手法があり、それらはすべて標準SQLです。

NOT EXISTS

多くの場合、Postgresで最速です。

SELECT ip 
FROM   login_log l 
WHERE  NOT EXISTS (
   SELECT  -- SELECT list mostly irrelevant; can just be empty in Postgres
   FROM   ip_location
   WHERE  ip = l.ip
   );

次の点も考慮してください。

LEFT JOIN / IS NULL

時にはこれが最速です。多くの場合最短です。多くの場合、と同じクエリプランになりNOT EXISTSます。

SELECT l.ip 
FROM   login_log l 
LEFT   JOIN ip_location i USING (ip)  -- short for: ON i.ip = l.ip
WHERE  i.ip IS NULL;

EXCEPT

ショート。より複雑なクエリに簡単に統合することはできません。

SELECT ip 
FROM   login_log

EXCEPT ALL  -- "ALL" keeps duplicates and makes it faster
SELECT ip
FROM   ip_location;

ドキュメントごとに)注意してください:

EXCEPT ALLが使用されない限り、重複は排除されます。

通常は、ALLキーワードが必要になります。気にしない場合でも、クエリが高速になるため、引き続き使用してください。

NOT IN

NULL値なしで、またはNULL適切に処理することがわかっている場合にのみ有効です。私は考えていない、この目的のためにそれを使用します。また、テーブルが大きくなるとパフォーマンスが低下する可能性があります。

SELECT ip 
FROM   login_log
WHERE  ip NOT IN (
   SELECT DISTINCT ip  -- DISTINCT is optional
   FROM   ip_location
   );

NOT INNULL両側の値の「トラップ」を運ぶ:

MySQLを対象としたdba.SEに関する同様の質問:


2
どちらのSQLも、両方のテーブルでデータ量が多いことを考えると、より速く実行されます。(数十億で想定)
Teja 2016

EXCEPT ALLが私にとって最速だった
Dan Parker

注意してください。LEFT JOINルックアップテーブルに一致する行が複数ある場合、一致しない行ごとにメインクエリに重複したエントリが作成されますが、これは望ましくない場合があります。
Matthias Fripp

@MatthiasFripp:これがで発生することは決してないことを除いてWHERE i.ip IS NULLまったく一致しません
Erwin Brandstetter

@ erwin-brandstetter:いいですね。私は複数の肯定的な一致の可能性について考えてつまずきましたが、もちろんそれらはすべて除外されます。
マティアスフリップ

2

A.)コマンドが存在しません。'S 'がありません。

B.)代わりにNOT INを使用する

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;

4
大規模なデータセットに対してNOT INを行うのはひどい考えです。とても、とても遅い。それは悪いことであり、避けるべきです。
Grzegorz Grabek

0

SELECT * FROM testcases1 t WHERE NOT EXISTS ( SELECT 1
FROM executions1 i WHERE t.tc_id = i.tc_id and t.pro_id=i.pro_id and pro_id=7 and version_id=5 ) and pro_id=7 ;

ここで、testcases1テーブルにはすべてのデータが含まれ、executions1テーブルにはtestcases1テーブルの一部のデータが含まれています。exections1テーブルに存在しないデータのみを取得しています。(そして、私もあなたが与えることができるいくつかの条件を与えています。)データを取得する際に存在してはならない条件を括弧内に指定します。


0

これも試すことができます...

SELECT l.ip, tbl2.ip as ip2, tbl2.hostname
FROM   login_log l 
LEFT   JOIN (SELECT ip_location.ip, ip_location.hostname
             FROM ip_location
             WHERE ip_location.ip is null)tbl2

2
WHERE ip_location.ip is null-どのようにしてWHERE条件が真になることができますか?また、サブクエリは相関クエリではありません。
Istiaque Ahmed 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.