PostgreSQL 'NOT IN' und Unterabfrage

87

Ich versuche diese Abfrage auszuführen:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (select consols.mac from consols)

Aber ich bekomme keine Ergebnisse. Ich habe es getestet und weiß, dass etwas mit der Syntax nicht stimmt. In MySQL funktioniert eine solche Abfrage perfekt. Ich habe eine Zeile hinzugefügt, um sicherzugehen, dass es eine macgibt, die nicht in der consolsTabelle vorhanden ist, aber dennoch keine Ergebnisse liefert .

Skowron-Linie
quelle
4
Ist die consols.macSpalte NULLoder NOT NULL?
Mark Byers

Antworten:

162

Wenn Sie NOT IN verwenden, sollten Sie sicherstellen, dass keiner der Werte NULL ist:

SELECT mac, creation_date 
FROM logs 
WHERE logs_type_id=11
AND mac NOT IN (
    SELECT mac
    FROM consols
    WHERE mac IS NOT NULL -- add this
)
Mark Byers
quelle
4
Hinweis: Die WHERE mac IS NOT NULLKlausel in der Unterabfrage wird nicht benötigt, da In(...)immer NULL-Werte (und Duplikate) entfernt werden. Weil ein Set keine NULL-
Werte
7
@ Wildplasser Ich weiß nicht darüber. Es hat bei mir nicht funktioniert, bis ich das hinzugefügt habe IS NOT NULL. Die Verschachtelten SELECTkehrten ein paar zurück NULLS, und das stolperte über die IN(SELECT...).
robins35
2
Ich würde mich sehr über eine Erklärung freuen, warum IS NOT NULLdies funktioniert.
Mbarkhau
7
Es scheint, dass die Verwendung NULLin einer NOT INKlausel nicht funktioniert, da ein Vergleich mit NULLweder wahr noch falsch ist. sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau
2
Die Abfrage gibt keine Zeilen zurück, is not nullwenn die Unterabfrage keine übereinstimmenden Werte und mindestens einen nullWert erzeugt. Aus Abschnitt 9.22 des aktuellen PostgreSQL-Handbuchs (Version 10): "[…] Wenn es keine gleichen Werte für die rechte Hand gibt und mindestens eine rechte Zeile null ergibt, ist das Ergebnis des Konstrukts NOT IN null und nicht wahr . "
Christopher Lewis
29

Wenn Sie NOT IN verwenden, sollten Sie auch NOT EXISTS berücksichtigen, das die Nullfälle still behandelt. Siehe auch PostgreSQL Wiki

SELECT mac, creation_date 
FROM logs lo
WHERE logs_type_id=11
AND NOT EXISTS (
  SELECT *
  FROM consols nx
  WHERE nx.mac = lo.mac
  );
Wildplasser
quelle
3
Beachten Sie auch einen großen Leistungsverlust bei der Verwendung von NOT EXISTSvs... NOT IN
IcanDivideBy0
1
@ IcanDivideBy0 In den meisten Fällen generieren sie denselben Abfrageplan. Hast du es getestet?
Wildplasser
1
Es gibt auch einen Leistungsgewinn bei der Verwendung von NOT IN anstelle von NOT EXISTS bei Unterabfragen. Siehe wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Gerbrand
8

Sie können auch die Bedingung LEFT JOIN und IS NULL verwenden:

SELECT 
  mac, 
  creation_date 
FROM 
  logs
    LEFT JOIN consols ON logs.mac = consols.mac
WHERE 
  logs_type_id=11
AND
  consols.mac IS NULL;

Ein Index für die "Mac" -Spalten kann die Leistung verbessern.

Frank Heikens
quelle