Вопрос SQL-запроса: SELECT ... NOT IN - PullRequest
37 голосов
/ 17 ноября 2008

Я уверен, что сделал глупую ошибку, но я не могу понять, что:

В SQL Server 2005 я пытаюсь выбрать всех клиентов, кроме тех, кто сделал бронирование до 2 часов ночи.

Когда я запускаю этот запрос:

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

Я получаю 0 результатов.

Но

SELECT idCustomer FROM reservations 

возвращает 152.000 результатов, а часть "NOT IN":

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

возвращает только 284 строки

Ответы [ 7 ]

64 голосов
/ 17 ноября 2008
SELECT distinct idCustomer FROM reservations
WHERE DATEPART ( hour, insertDate) < 2
  and idCustomer is not null

Убедитесь, что ваш параметр списка не содержит нулевых значений.

Вот объяснение:

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

совпадает с:

WHERE NOT (field1 = 1 OR field1 = 2 OR field1 = 3 OR field1 = null)
  • Это последнее сравнение оценивается как ноль.
  • Это значение равно OR для остальной части логического выражения, что дает значение NULL. (*)
  • ноль отрицается, давая ноль.
  • ноль не соответствует истине - предложение where содержит только истинные строки, поэтому все строки фильтруются.

(*) Редактировать: это объяснение довольно хорошее, но я хотел бы остановиться на одной вещи, чтобы предотвратить будущие придирки. (ИСТИНА ИЛИ НУЛЬ) оценивается как ИСТИНА. Это актуально, например, если field1 = 3. Это значение TRUE будет сведено к нулю, а строка будет отфильтрована.

6 голосов
/ 17 ноября 2008

Всегда опасно иметь NULL в списке IN - оно часто ведет себя как ожидалось для IN, но не для 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)'
2 голосов
/ 17 ноября 2008

Учитывая, что это SQL 2005, вы также можете попробовать это Это похоже на команду Oracle MINUS (противоположно UNION)

Но я бы также предложил добавить столбец DATEPART (hour, insertDate) для отладки

SELECT idCustomer FROM reservations 
EXCEPT
SELECT idCustomer FROM reservations WHERE DATEPART ( hour, insertDate) < 2
0 голосов
/ 04 июля 2017
select * from table_name where id=5 and column_name not in ('sandy,'pandy');
0 голосов
/ 19 января 2017
SELECT MIN(A.maxsal) secondhigh
FROM (
      SELECT TOP 2 MAX(EmployeeBasic) maxsal
      FROM M_Salary
      GROUP BY EmployeeBasic
      ORDER BY EmployeeBasic DESC
     ) A
0 голосов
/ 17 ноября 2008

Извините, если я упустил момент, но разве следующие не сделают то, что вы хотите самостоятельно?

SELECT distinct idCustomer FROM reservations 
WHERE DATEPART(hour, insertDate) >= 2
0 голосов
/ 17 ноября 2008
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

[Обновление: добавлены дополнительные критерии для обработки idCustomer, который имеет значение NULL, что, по-видимому, и было главной проблемой оригинального плаката]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...