PostgreSQL 'NOT IN' e sottoquery


91

Sto cercando di eseguire questa query:

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

Ma non ottengo risultati. L'ho testato e so che c'è qualcosa di sbagliato nella sintassi. In MySQL una simile query funziona perfettamente. Ho aggiunto una riga per essere sicuro che ce n'è una macche non esiste nella consolstabella, ma ancora non dà alcun risultato.


4
La consols.maccolonna è NULLo NOT NULL?
Mark Byers

Risposte:


169

Quando si utilizza NOT IN è necessario assicurarsi che nessuno dei valori sia NULL:

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
)

4
Nota: la WHERE mac IS NOT NULLclausola nella sottoquery non è necessaria, poiché In(...)rimuove sempre NULL (e duplicati). Perché un set non può contenere NULL
wildplasser

7
@wildplasser Non lo so. Non funzionava per me, finché non ho aggiunto il file IS NOT NULL. Il nidificato SELECTstava restituendo alcuni NULLS, e questo stava facendo inciampare il file IN(SELECT...).
robins35

2
Apprezzerei molto una spiegazione del motivo per cui IS NOT NULLquesto funziona.
mbarkhau

7
Sembra che l'utilizzo NULLin una NOT INclausola non funzioni perché un confronto con NULLnon è né vero né falso. sqlbadpractices.com/using-not-in-operator-with-null-values
mbarkhau

2
La query non restituirà alcuna riga in assenza di is not nullse la sottoquery non produce valori corrispondenti e almeno un nullvalore. Dalla sezione 9.22 del manuale PostgreSQL corrente (versione 10): "[…] se non ci sono valori uguali a destra e almeno una riga a destra restituisce null, il risultato del costrutto NOT IN sarà null, non vero . "
Christopher Lewis,

29

Quando si utilizza NOT IN, si dovrebbe anche considerare NOT EXISTS, che gestisce i casi nulli in silenzio. Vedi anche 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
  );

3
Notare anche un'enorme perdita di prestazioni quando si utilizza NOT EXISTSvs... NOT IN
IcanDivideBy0

1
@ IcanDivideBy0 Nella maggior parte dei casi generano lo stesso piano di query. L'hai provato?
wildplasser

1
C'è anche un miglioramento delle prestazioni nell'uso di NOT IN invece di NOT EXISTS, in caso di sottoquery. Vedi wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_NOT_IN
Gerbrand

8

Puoi anche usare una condizione LEFT JOIN e IS NULL:

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

Un indice sulle colonne "mac" potrebbe migliorare le prestazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.