NOT IN не работает должным образом для строкового столбца типа mysql - PullRequest
0 голосов
/ 22 марта 2020

Я нашел что-то странное между NOT IN и IN, где я использую столбец строкового типа. Он отлично работает для IN, но не для NOT IN. Хотя оба метода (NOT IN и IN) для столбца с целочисленным типом

SELECT * FROM `table1` t1 where t1.email not in (select t2.email from `table2` t2)

не возвращают никакого результата из t1, существующего в t2, хотя это должно происходить, поскольку имеются подходящие записи, тогда как

SELECT * FROM `table1` t1 where t1.email in (select t2.email from `table2` t2)

возвращает записи из t1, которые находятся в t2.

Ответы [ 3 ]

2 голосов
/ 22 марта 2020

Вот простой пример, объясняющий это появление, которое также встречается в других СУБД, таких как SQL Сервер и Oracle.

. Предположим, что

select t2.email from `table2` t2

возвращает

+-------------+
| email       |
+-------------+
| 111@abc.com |
| 222@abc.com |
| NULL        |
+-------------+

При выполнении

SELECT * FROM `table1` t1 where t1.email not in (select t2.email from `table2` t2)

MySQL преобразует его в

SELECT * FROM `table1` t1 
where 
t1.email <> '111@abc.com' AND t1.email <> '222@abc.com' AND t1.email <> NULL

Предложение where всегда возвращает NULL, поскольку любое значение, сравниваемое с NULL, возвращает NULL и любое логическое значение, выполняющее AND операцию с NULL, также возвращает NULL. Поэтому весь запрос SQL, как показано выше, всегда возвращает не запись.

Аналогично,

SELECT * FROM `table1` t1 where t1.email in (select t2.email from `table2` t2)

будет преобразовано в

SELECT * FROM `table1` t1 
where 
t1.email = '111@abc.com' OR t1.email = '222@abc.com' OR t1.email <> NULL

Значение t1.email <> NULL равно NULL, которое будет игнорироваться, если любое другое сравнение равно TRUE.

1 голос
/ 22 марта 2020

Изменение запроса к приведенному ниже сработало.

SELECT * 
  FROM table1 t1 
 WHERE t1.email NOT IN ( SELECT t2.email 
                           FROM table2 t2 
                          WHERE t2.email IS NOT NULL )

Поскольку значение столбца электронной почты в table2 было NULL для одной строки, которая не возвращала записей.

0 голосов
/ 22 марта 2020

Не используйте NOT IN с подзапросами. Причина проста: он не обрабатывает NULL значения, как ожидал бы пользователь.

Вместо этого просто привыкните к использованию NOT EXISTS:

SELECT t1.*
FROM `table1` t1 
WHERE NOT EXISTS (SELECT 1
                  FROM `table2` t2
                  WHERE t1.email= t2.email 
                 ) ;

Почему это не работает, как ожидалось? Это связано с тем, как SQL определяет NULL значений. Они имеют семантику «неизвестного» значения, а не «отсутствующего» значения.

Рассмотрим следующие условия:

  • 1 IN (1, 2) - оценивается как истинное
  • 3 IN (1, 2) - оценивается как ложное

NULL с не влияет на это, потому что это точное совпадение:

  • 1 IN (1, 2, NULL) - оценивается в true
  • 3 IN (1, 2, NULL) - оценивается как NULL, что считается ложным

Но NULL s влияют на NOT IN

  • 1 NOT IN (1, 2, NULL) - оценивается как ложное
  • 3 NOT IN (1, 2, NULL) - оценивается как NULL, потому что NULL "неизвестно"

Ключ в том, что NULL не имеет спецификаций c значение - значит «неизвестно». Таким образом, NULL может быть равно 3. Следовательно, результат последнего выражения "неизвестен" (то есть NULL), а не "истина".

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