2011-03-08 11 views
52

Tengo dos bases de datos, una que contiene el inventario y otra que contiene un subconjunto de los registros de la base de datos primaria.SQL NOT IN no funciona

La siguiente instrucción SQL no está funcionando:

SELECT stock.IdStock 
     ,stock.Descr  
FROM [Inventory].[dbo].[Stock] stock 
WHERE stock.IdStock NOT IN 
     (SELECT foreignStockId FROM 
     [Subset].[dbo].[Products]) 

El no en no funciona. Eliminar el NOT proporciona los resultados correctos, es decir, productos que están en ambas bases de datos. Sin embargo, usar NOT IN no devuelve CUALQUIER resultado.

¿Qué estoy haciendo mal, alguna idea?

+0

¿Estás seguro de que tienes stock.IdStock que no están en foreignStockId en absoluto? – CloudyMarble

+0

¿Realmente tiene algún elemento en 'Inventario' que no esté en 'Subconjunto'? –

+1

Explique qué debe devolver la consulta. Actualmente devuelve todos los elementos de stock donde no hay ningún producto en el subconjunto que hace referencia a él. –

Respuesta

125
SELECT foreignStockId 
FROM [Subset].[dbo].[Products] 

devuelve Probablemente un NULL.

Una consulta NOT IN no devolverá ninguna fila si existe NULL en la lista de valores NOT IN. Puede excluirlos explícitamente usando IS NOT NULL como se muestra a continuación.

SELECT stock.IdStock, 
     stock.Descr 
FROM [Inventory].[dbo].[Stock] stock 
WHERE stock.IdStock NOT IN (SELECT foreignStockId 
          FROM [Subset].[dbo].[Products] 
          WHERE foreignStockId IS NOT NULL) 

O reescriba usando NOT EXISTS en su lugar.

SELECT stock.idstock, 
     stock.descr 
FROM [Inventory].[dbo].[Stock] stock 
WHERE NOT EXISTS (SELECT * 
        FROM [Subset].[dbo].[Products] p 
        WHERE p.foreignstockid = stock.idstock) 

Además de contar con la semántica que desea que el plan de ejecución de NOT EXISTS es a menudo más simple as looked at here.

El motivo de la diferencia de comportamiento se debe al three valued logic utilizado en SQL. Los predicados pueden evaluar a True, False o Unknown.

cláusula A WHERE debe evaluar a True para que la fila que ser devueltos, pero esto no es posible con NOT IN cuando NULL está presente como se explica a continuación.

'A' NOT IN ('X','Y',NULL) es equivalente a 'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)

  • 'A' <> 'X' = True
  • 'A' <> 'Y' = True
  • 'A' <> NULL = Unknown

True AND True AND Unknown evalúa a Unknown p er el truth tables for three valued logic.

Los siguientes enlaces tienen alguna discusión adicional sobre el rendimiento de las diversas opciones.

+0

Eso lo tiene, salud. – Sam

+0

Esto lo arregló para mí. Seleccione * De x Donde x.y no está en (Seleccione Distinto ISNULL (c, 0)) – Spaceman

+0

El IS NOT NULL es la sub consulta que hace el truco. Gracias – rikket

2

Si NO EN no funciona, siempre se puede tratar de hacer LEFT JOIN. Luego filtre por WHERE utilizando uno de los valores de la tabla unida, que son NULL. Siempre que el valor que se estaba uniendo por no contenga ningún valor de NULO.