Spesso è necessario formare query in cui i criteri di filtraggio sono determinati dinamicamente: l'elenco di valori è fornito dall'utente dell'interfaccia e i valori mancanti (NULL) devono poter comparire o meno nel risultato. Questa query deve funzionare rapidamente su grandi volumi e deve essere corretta dal punto di vista semantico SQL.
La combinazione scorretta delle condizioni IN, NOT IN e la verifica su NULL porta a risultati inaspettati poiché in SQL l'espressione "NULL IN (...)" restituisce sempre UNKNOWN, e "NOT IN" può portare a un risultato vuoto se almeno uno degli elementi dell'elenco è NULL. Le prestazioni su grandi dataset possono deteriorarsi drasticamente con condizioni scritte in modo inefficace.
La combinazione corretta appare così:
SELECT * FROM sales WHERE region IN ('Moscow','Samara') OR region IS NULL;
SELECT * FROM sales WHERE (region NOT IN ('Moscow','Samara') OR region IS NULL);
SELECT * FROM sales WHERE region NOT IN ('Moscow','Samara') AND region IS NOT NULL;
Caratteristiche chiave:
Cosa succede se si verifica "WHERE field NOT IN ('a', NULL)"?
Il risultato è sempre vuoto, poiché qualsiasi riga viene confrontata con NULL nell'elenco, dando UNKNOWN e filtrando tutto.
Esempio di codice:
SELECT * FROM test WHERE name NOT IN ('Ivan', NULL);
Restituirà "IN (NULL,...)" un valore per righe con NULL?
No. L'espressione NULL IN (...) restituisce sempre UNKNOWN, e non TRUE.
Come accelerare il filtraggio su un grande elenco di valori?
Utilizzare indici e preferibilmente applicare JOIN con una tabella temporanea, se l'elenco è ampio (centinaia/migliaia di valori) — questo accelera il filtraggio rispetto a un lungo IN.
Nel rapporto analitico è stata applicata "WHERE city NOT IN ('London', field_2, NULL)". Risultato finale: nessun risultato, nessuno riusciva a capire a lungo il motivo della perdita di righe.
Pro:
Contro:
Nel CRM è stato scelto un elenco di regioni clienti e aggiunto un pulsante aggiuntivo "Includi valori non compilati". La logica di filtraggio:
... WHERE city IN ('SPB','NNov') OR city IS NULL
Pro:
Contro: