2008-11-17 11 views
30

Estoy seguro de cometer un error tonto, pero no puedo entender lo que:SQL: SELECT ... NO EN

En SQL Server 2005 que estoy tratando de selección de todos los clientes, excepto aquellos que han hecho una reserva antes 2 a. M.

Cuando ejecuta esta consulta:

SELECT idCustomer FROM reservations 
WHERE idCustomer NOT IN 
    (SELECT distinct idCustomer FROM reservations 
    WHERE DATEPART (hour, insertDate) < 2) 

llego 0 resultados.

Pero

SELECT idCustomer FROM reservations 

rendimientos 152.000 resultados y las "no en" parte:

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 

devuelve sólo 284 filas

+0

¿Por qué poner una clara en ti NO EN? Es el 5 en (1, 1, 2, 2, 3, 4, 4, 4, 4, 4)? En no importa si hay duplicados. –

+1

Claro, me estaba poniendo un poco desesperado y tratando de todo :) –

Respuesta

53
SELECT distinct idCustomer FROM reservations 
WHERE DATEPART (hour, insertDate) < 2 
    and idCustomer is not null 

Asegúrese de que el parámetro lista no contiene nula valores.

He aquí una explicación:

WHERE field1 NOT IN (1, 2, 3, null) 

es lo mismo que:

WHERE NOT (field1 = 1 OR field1 = 2 OR field1 = 3 OR field1 = null) 
  • Esa última comparación se evalúa como null.
  • Ese nulo está OR con el resto de la expresión booleana, produciendo nulo. (*)
  • nulo es negado, produciendo nulo.
  • null no es verdadero - la cláusula where solo conserva las filas verdaderas, por lo que se filtran todas las filas.

(*) Edición: esta explicación es bastante buena, pero deseo abordar una cosa para evitar futuros errores. (VERDADERO O NULO) evaluaría VERDADERO. Esto es relevante si field1 = 3, por ejemplo. Ese valor VERDADERO sería negado a FALSO y la fila sería filtrada.

+0

¡Eso fue todo, gracias! Todavía no entiendo por qué. Los valores nulos no deben ser filtrados por los nulos, ¿verdad? –

+0

Gran explicación David, muchas gracias! –

2

Dado que es SQL 2005, también puede probar este Es similar al comando MENOS de Oracle (enfrente de UNION)

Pero también sugiere que se añada la columna de la DATEPART (hora, insertDate) para la depuración

SELECT idCustomer FROM reservations 
EXCEPT 
SELECT idCustomer FROM reservations WHERE DATEPART (hour, insertDate) < 2 
0
SELECT Reservations.idCustomer FROM Reservations (nolock) 
LEFT OUTER JOIN @reservations ExcludedReservations (nolock) ON Reservations.idCustomer=ExcludedReservations.idCustomer AND DATEPART(hour, ExcludedReservations.insertDate) < 2 
WHERE ExcludedReservations.idCustomer IS NULL AND Reservations.idCustomer IS NOT NULL 
GROUP BY Reservations.idCustomer 

[actualización: Añadido criterios adicionales para manejar idCustomer ser NULL, que aparentemente era el principal problema el cartel original tenía]

+0

Hola Kevin, el problema era que customerId era nulo y como @David señaló, ¡pero muchas gracias de todos modos! –

+0

Ok. Agregado en los criterios adicionales solo por completitud :-P No tengo los datos para probarlo, pero me gustaría ver la diferencia en los planes de EJECUCIÓN de NOT IN versus OUTER JOIN. De todos modos, me alegro de que se haya resuelto su problema. –

0

Disculpe si me he perdido el punto, pero ¿no haría lo siguiente lo que quiere por sí mismo?

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART(hour, insertDate) >= 2 
+0

Estaba pensando lo mismo ... Sin embargo, si un cliente tiene dos reservas, una antes de 2 Am y una después, la suya lo incluirá y la suya no. –

+0

¡Ah, eso tiene sentido, mi cerebro no está disparando en todos los cilindros hoy! –

6

Siempre es peligroso tener NULL en la lista IN - que a menudo se comporta como se esperaba para el IN pero no para el NOT IN:

IF 1 NOT IN (1, 2, 3, NULL) PRINT '1 NOT IN (1, 2, 3, NULL)' 
IF 1 NOT IN (2, 3, NULL) PRINT '1 NOT IN (2, 3, NULL)' 
IF 1 NOT IN (2, 3) PRINT '1 NOT IN (2, 3)' -- Prints 
IF 1 IN (1, 2, 3, NULL) PRINT '1 IN (1, 2, 3, NULL)' -- Prints 
IF 1 IN (2, 3, NULL) PRINT '1 IN (2, 3, NULL)' 
IF 1 IN (2, 3) PRINT '1 IN (2, 3)' 
+0

Buen punto. Sin embargo, nunca me he encontrado con un caso en el que el uso de null en la lista de dentro haya dado una respuesta más correcta. –

+0

Exactamente - el problema es cuando la lista es dinámica y usted no sabe que el NULO está allí y usted toma una ENTRADA y la cambia a un NO EN. –

-1
SELECT MIN(A.maxsal) secondhigh 
FROM (
     SELECT TOP 2 MAX(EmployeeBasic) maxsal 
     FROM M_Salary 
     GROUP BY EmployeeBasic 
     ORDER BY EmployeeBasic DESC 
    ) A 
+3

Bienvenido a SO. Es posible que desee leer este http://stackoverflow.com/help/how-to-answer sobre cómo redactar buenas respuestas. Las respuestas de solo código no son muy útiles, puede agregar una breve descripción de cómo soluciona el problema. – thebenman

-1
select * from table_name where id=5 and column_name not in ('sandy,'pandy'); 
+1

Bienvenido a SO. Es posible que desee leer este stackoverflow.com/help/how-to- answer sobre cómo redactar buenas respuestas. Las respuestas con solo el código no son muy útiles; puede agregar una breve descripción de cómo soluciona el problema. – GhostCat