2011-04-21 19 views
25

Necesito crear una consulta que me muestre los registros que están en la Tabla 1, pero que no están en la Tabla 2, en función de la combinación del número de serie del modelo de fabricación.Servidor SQL - NO EN

Sé de hecho que hay 4 registros que difieren, pero mi consulta siempre vuelve en blanco.

SELECT * 
FROM Table1 WHERE MAKE+MODEL+[Serial Number] NOT IN 
(SELECT make+model+[serial number] FROM Table2) 

La tabla 1 tiene 5 registros.

Cuando cambio la consulta a IN, obtengo 1 registro. ¿Qué estoy haciendo mal con el NOT?

+3

¿Tiene valores nulos en sus tablas? – tobias86

+0

tal vez publicar sus datos ayudará. la sintaxis se ve bien (aunque la tecla psuedo es un poco graciosa) – Randy

Respuesta

35

Es por the way NOT IN works.

Para evitar estos dolores de cabeza (y para una consulta rápida en muchos casos), siempre prefieren no existe:

SELECT * 
FROM Table1 t1 
WHERE NOT EXISTS (
    SELECT * 
    FROM Table2 t2 
    WHERE t1.MAKE = t2.MAKE 
    AND t1.MODEL = t2.MODEL 
    AND t1.[Serial Number] = t2.[serial number]); 
+0

eso es todo! ¡Gracias! –

+0

Ver mis ediciones (Mejoré mi respuesta después de leer la buena respuesta de Joe) –

0

Use una UNIÓN IZQUIERDA que compruebe el lado derecho para valores nulos.

SELECT a.Id 
FROM TableA a 
LEFT JOIN TableB on a.Id = b.Id 
WHERE b.Id IS NULL 

Lo anterior se correspondería a la Tabla A y la Tabla B sobre la base de la columna ID en cada uno, y luego le dan las filas en las que el lado B está vacío.

+0

Esto generalmente funciona, pero IMO no es una buena solución general al problema porque puede dar como resultado filas duplicadas para TableA si existen múltiples filas en TableB para el predicado de unión, y si b . Si sucede que es una columna que admite nulos, puede obtener un falso positivo. Sin embargo, es una solución válida para este problema en muchos casos (según los datos) –

+0

@DaveMarkle, sí, muy buenas advertencias, gracias. –

6

Probablemente sea mejor que compare los campos individualmente, en lugar de concatenar las cadenas.

SELECT t1.* 
    FROM Table1 t1 
     LEFT JOIN Table2 t2 
      ON t1.MAKE = t2.MAKE 
       AND t1.MODEL = t2.MODEL 
       AND t1.[serial number] = t2.[serial number] 
    WHERE t2.MAKE IS NULL 
+0

mejor - ¿como en más rápido? :) –

+0

Me gusta esta idea – tobias86

+0

@xrum: Con los índices en las columnas, ciertamente creo que sí. –

0

Un problema podría ser que si cualquiera marca, modelo, o [número de serie] eran nulos , los valores nunca serían devueltos Debido a que las concatenaciones de cadenas con valores nulos siempre dan como resultado nulo, y no en() con nulo, siempre no devuelve nada. El remedio para esto es utilizar un operador como IsNull (marca, '') + IsNull (Modelo ''), etc.

1
SELECT [T1].* 
FROM [Table1] AS [T1] 
WHERE NOT EXISTS (SELECT 
    1 AS [C1] 
    FROM [Table2] AS [T2] 
    WHERE ([T2].[MAKE] = [T1].[MAKE]) AND 
     ([T2].[MODEL] = [T1].[MODEL]) AND 
     ([T2].[Serial Number] = [T1].[Serial Number]) 
); 
1
SELECT * FROM Table1 
WHERE MAKE+MODEL+[Serial Number] not in 
    (select make+model+[serial number] from Table2 
    WHERE make+model+[serial number] IS NOT NULL) 

que trabajó para mí, donde make+model+[serial number] era un nombre de campo