Transact-SQL: NOT IN in a nested select
Occorre fare attenzione alla clausola NOT IN, quando l’insieme dei dati in cui viene eseguito il controllo è una select a sua volta. Se la SELECT interna contiene valori null non viene restituito nessun record.
Qualche query su due tabelle di esempio:
CREATE TABLE TABELLA1 (id INT, descr VARCHAR(11)) INSERT INTO tabella1 VALUES (1, 'pippo') INSERT INTO tabella1 VALUES (1, 'pluto') INSERT INTO tabella1 VALUES (1, 'paperino') |
ID | DESCR |
---|---|
1 | pippo |
1 | pluto |
1 | paperino |
CREATE TABLE TABELLA2 (id INT, descr VARCHAR(11)) INSERT INTO tabella2 VALUES (2, 'pippo') INSERT INTO tabella2 VALUES (2, 'pluto') |
ID | DESCR |
---|---|
2 | pippo |
2 | pluto |
Se voglio prendere tutti i record di TABELLA1 che non hanno una descrizione in TABELLA2 posso scrivere così:
SELECT * FROM tabella1 t1 WHERE t1.descr NOT IN (SELECT t2.descr FROM tabella2 t2) |
E ottengo il risultato:
ID | DESCR |
---|---|
1 | paperino |
che è coerente con la query. Adesso inserisco una riga con valore null nel campo DESCR in TABELLA2;
INSERT INTO tabella2 VALUES (2,NULL) |
Ora la stessa query restituisce un recordset vuoto, sbagliando.
Per continuare ad usare il NOT IN occorre inserire la condizione di IS NOT NULL alla select interna:
SELECT * FROM tabella1 t1 WHERE t1.descr NOT IN (SELECT t2.descr FROM tabella2 t2 WHERE t2.descr IS NOT NULL) |
Ora il recordset è di nuovo coerente con la query.
Una alternativa al NOT IN è il JOIN diretto fra le tabelle:
SELECT t1.* FROM tabella1 t1 LEFT JOIN tabella2 t2 ON (t1.descr = t2.descr) WHERE t2.descr IS NULL |
oppure utilizzando la clausola EXCEPT:
SELECT descr FROM tabella1 EXCEPT SELECT descr FROM tabella2 |
Il problema, ad onore del vero, non è solo di SQLServer, ma è condiviso anche da altri DBMS.
Leave a Reply