SQL Server – SELECT NOT IN

Estaba hoy haciendo unas consultas de SQL, y me he encontrado con el problemilla que os cuento a continuación.

En concreto,necesitaba un listado de los modelos que no están asociados a ninguna carrocería. Para ello, lo que hago es un SELECT de la tabla de modelos donde la condición del WHERE es que no estén en la tabla de carrocerías (el típico SELECT WHERE NOT IN). Algo parecido a lo siguiente:


SELECT    idmodelo
FROM    modelos
WHERE    idmodelo NOT IN (
 SELECT DISTINCT idmodelo
 FROM carrocerias
)

Mi sorpresa ha sido mayúscula cuando al ejecutar la consulta no salía ningún resultado, ya que sabía a ciencia cierta que había muchos modelos sin ninguna carrocería asociada. He emepzado a darle vueltas, a hacer pruebas varias, y al final he encontrado en un post de Stackoverflow el origen del problema y su solución.

¿Por qué ocurre esto? En la tabla de carrocerías, hay muchas que en su clave de referencia externa a modelo tienen el valor NULL. Al hacer el NOT IN, se intenta comparar el valor del idmodelo con NULL. Si la variable ansi_nulls está activa, la comparación de cualquier valor con NULL da como resultado UNKNOWN. Por eso, al hacer la consulta anterior no salía ningún resultado.

Para evitar esto, en la subconsulta hay que poner en al claúsula WHERE, el “IS NOT NULL”.  Al final todo queda así:


SELECT    idmodelo
FROM    modelo
WHERE    idmodelo NOT IN (
 SELECT DISTINCT idmodelo
 FROM carrocerias
 WHERE idmodelo IS NOT NULL
)

Y ahora sí … el resultado es el esperado :-)

NOTA ADICIONAL: Como bien apunta Ezequiel en el primer comentario (¡muchas gracias!), una manera de hacer esto mismo que pongo en el post con mucho mejor rendimiento es hacer un LEFT JOIN entre las tablas modelos y carrocerías. Quedaría así:


SELECT  modelo.idmodelo
FROM    modelo LEFT JOIN carrocerias ON
 modelo.idmodelo = carrocerias.idmodelo
WHERE   carrocerias.idmodelo IS NULL

El LEFT JOIN siempre y cuando se haga sobre campos que tengan algún tipo de índice va a dar un mejor rendimiento normalmente que una subquery. En cualquier caso, ante la duda, siempre debéis mirar el planificador de consultas de SQL.

El hacerlo de la manera que yo ponía es porque para darle claridad al caso la consulta estaba simplificada. En realidad, la subquery hacía unas cuántas cosillas más.

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

Tags:

Si te gustó esta entrada anímate a escribir un comentario o suscribirte al feed y obtener los artículos futuros en tu lector de feeds.

Comentarios

[...] http://www.analizando.me/sql-server-select-not-in/ November 3, 2010   //   MsSQL   //   No Comments   //   [...]

Ruben, creo que otra forma de hacerlo con algo de mejor performace (si no me equivoco) podría ser esta:

SELECT modelo.idmodelo
FROM modelo LEFT JOIN carrocerias ON
modelo.idmodelo = carrocerias.idmodelo
WHERE carrocerias.idmodelo IS NULL

obviamente considerando el hecho que la columna idmodelo en carrocerias es un foreignkey vinculado a modelo.

Hola Ezequiel, muchas gracias por tu comentario. He añadido una nota para reflejarlo.

Gracias, me has ahorrado mucho tiempo, ya no sabía que pasaba con el NOT IN…

Muchas gracias! me fue de gran ayuda

Escribe un comentario

(requerido)

(requerido)