Wählen Sie Zeilen aus, die in anderen Tabellen nicht vorhanden sind

172

Ich habe zwei Postgresql-Tabellen:

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

Ich möchte jede IP-Adresse erhalten, von login_logder keine Zeile vorhanden ist ip_location.
Ich habe diese Abfrage versucht, aber sie löst einen Syntaxfehler aus.

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`

Ich frage mich auch, ob diese Abfrage (mit Anpassungen, damit sie funktioniert) die leistungsstärkste Abfrage für diesen Zweck ist.

stUrb
quelle

Antworten:

385

Grundsätzlich gibt es 4 Techniken für diese Aufgabe, alle Standard-SQL.

NOT EXISTS

Oft am schnellsten in 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
   );

Beachten Sie auch:

LEFT JOIN / IS NULL

Manchmal ist das am schnellsten. Oft am kürzesten. Führt häufig zum gleichen Abfrageplan wie 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

Kurz. Nicht so einfach in komplexere Abfragen zu integrieren.

SELECT ip 
FROM   login_log

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

Beachten Sie Folgendes ( gemäß Dokumentation ):

Duplikate werden entfernt, sofern sie nicht EXCEPT ALLverwendet werden.

In der Regel möchten Sie das ALLSchlüsselwort. Wenn es Sie nicht interessiert, verwenden Sie es trotzdem, da dies die Abfrage beschleunigt .

NOT IN

Nur gut ohne NULLWerte oder wenn Sie wissen, wie man NULLrichtig damit umgeht. Ich würde es nicht für diesen Zweck verwenden.Außerdem kann sich die Leistung bei größeren Tabellen verschlechtern.

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

NOT IN trägt eine "Falle" für NULL Werte auf beiden Seiten:

Ähnliche Frage zu dba.SE für MySQL:

Erwin Brandstetter
quelle
2
Welches SQL würde schneller laufen, wenn man bedenkt, dass die Datenmengen in beiden Tabellen hoch sind. (unter der Annahme in Milliarden)
Teja
AUSSER ALLES war für mich am schnellsten
Dan Parker
Seien Sie vorsichtig mit LEFT JOIN- Wenn die Nachschlagetabelle mehrere übereinstimmende Zeilen enthält, wird in Ihrer Hauptabfrage für jede übereinstimmende Zeile ein doppelter Eintrag erstellt, der möglicherweise nicht erwünscht ist.
Matthias Fripp
@MatthiasFripp: Außer dass dies niemals mit auftreten kann WHERE i.ip IS NULL, was bedeutet, dass überhaupt keine Übereinstimmung vorliegt .
Erwin Brandstetter
@ erwin-brandstetter: Guter Punkt. Ich habe mich gestolpert und über die Möglichkeit mehrerer positiver Spiele nachgedacht, aber das wären natürlich alle ausgeschlossen.
Matthias Fripp
2

A.) Der Befehl ist NICHT EXISTIERT, Sie vermissen das 'S'.

B.) Verwenden Sie stattdessen NOT IN

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;
caleb.breckon
quelle
4
NOT IN bei großen Datenmengen ist eine schreckliche Idee. Sehr sehr langsam. Es ist schlecht und sollte vermieden werden.
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 ;

Hier enthält die Tabelle testcases1 alle Daten und die Tabelle executions1 enthält einige Daten aus der Tabelle testcases1. Ich rufe nur die Daten ab, die in der Tabelle exections1 nicht vorhanden sind. (und selbst ich gebe einige Bedingungen an, die Sie auch angeben können.) Geben Sie an, dass die Bedingung, die beim Abrufen von Daten nicht vorhanden sein sollte, in Klammern stehen sollte.

Deepak N.
quelle
0

Dies kann auch versucht werden ...

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
Ahnaf
quelle
2
WHERE ip_location.ip is null- Wie kann die WHEREBedingung jemals wahr sein? Außerdem ist die Unterabfrage keine korrelierte.
Istiaque Ahmed