Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

La selezione SQL dove non è presente nella sottoquery non restituisce alcun risultato

Aggiornamento:

Questi articoli nel mio blog descrivono le differenze tra i metodi in modo più dettagliato:

  • NOT IN rispetto a NOT EXISTS rispetto a LEFT JOIN / IS NULL :SQL Server
  • NOT IN rispetto a NOT EXISTS rispetto a LEFT JOIN / IS NULL :PostgreSQL
  • NOT IN rispetto a NOT EXISTS rispetto a LEFT JOIN / IS NULL :Oracle
  • NOT IN rispetto a NOT EXISTS rispetto a LEFT JOIN / IS NULL :MySQL

Esistono tre modi per eseguire una query del genere:

  • LEFT JOIN / IS NULL :

    SELECT  *
    FROM    common
    LEFT JOIN
            table1 t1
    ON      t1.common_id = common.common_id
    WHERE   t1.common_id IS NULL
    
  • NOT EXISTS :

    SELECT  *
    FROM    common
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    table1 t1
            WHERE   t1.common_id = common.common_id
            )
    
  • NOT IN :

    SELECT  *
    FROM    common
    WHERE   common_id NOT IN
            (
            SELECT  common_id
            FROM    table1 t1
            )
    

Quando table1.common_id non è nullable, tutte queste query sono semanticamente uguali.

Quando è nullable, NOT IN è diverso, poiché IN (e, quindi, NOT IN ) restituisce NULL quando un valore non corrisponde a nulla in un elenco contenente un NULL .

Questo può creare confusione ma può diventare più ovvio se ricordiamo la sintassi alternativa per questo:

common_id = ANY
(
SELECT  common_id
FROM    table1 t1
)

Il risultato di questa condizione è un prodotto booleano di tutti i confronti all'interno dell'elenco. Naturalmente, un singolo NULL value restituisce il NULL risultato che rende l'intero risultato NULL anche.

Non possiamo mai dire con certezza che common_id non è uguale a nulla di questo elenco, poiché almeno uno dei valori è NULL .

Supponiamo di avere questi dati:

common

--
1
3

table1

--
NULL
1
2

LEFT JOIN / IS NULL e NOT EXISTS restituirà 3 , NOT IN restituirà nulla (dal momento che valuterà sempre come FALSE o NULL ).

In MySQL , nel caso in una colonna non nullable, LEFT JOIN / IS NULL e NOT IN sono un po' (diverse percentuali) più efficienti di NOT EXISTS . Se la colonna è nullable, NOT EXISTS è il più efficiente (di nuovo, non molto).

In Oracle , tutte e tre le query producono gli stessi piani (un ANTI JOIN ).

In SQL Server , NOT IN / NOT EXISTS sono più efficienti, poiché LEFT JOIN / IS NULL non può essere ottimizzato per un ANTI JOIN dal suo ottimizzatore.

In PostgreSQL , LEFT JOIN / IS NULL e NOT EXISTS sono più efficienti di NOT IN , poiché sono ottimizzati per un Anti Join , mentre NOT IN utilizza hashed subplan (o anche un semplice subplan se la sottoquery è troppo grande per l'hash)