2016-03-10 1 views
3

Вот является sqlfiddle двух тестовых таблиц: http://sqlfiddle.com/#!9/33361/3Почему SQL-запрос с! = 0 не включает значения NULL?

ТЛ; др: почему делает SQL-запрос с != 0 не включают NULL значения?

Я ЛЕВАЯ ПРИСОЕДИНИТЬСЯ к двум таблицам. Я хотел бы видеть строки, которые либо имеют NULL в tableB.field1, либо 1 в tableB.field1, но исключают все, у кого есть 0 в tableB.field1.

Я думаю, что этот запрос (пример 6) должен дать мне этот результат, но он не получит нулевые записи.

SELECT * FROM tableA a 
LEFT JOIN tableB b ON a.id = b.join_id 
WHERE 
b.field1 != 0; 

Я должен использовать этот длинный запрос (пример 4):

SELECT * FROM tableA a 
LEFT JOIN tableB b ON a.id = b.join_id 
WHERE 
b.field1 != 0 OR b.field1 IS NULL; 

Просто интересно больше всего - как же MySQL не считает NULL быть = 0!?

Когда я переместить условный к пункту О, я получаю неожиданную строку:

mysql> SELECT * FROM tableA a 
    -> LEFT JOIN tableB b ON a.id = b.join_id AND b.field1 != 0; 
+------+--------+--------+---------+--------+--------+ 
| id | field1 | field2 | join_id | field1 | field2 | 
+------+--------+--------+---------+--------+--------+ 
| 1 | testA1 | testA1 |  1 | 1  | testB1 | 
| 2 | testA2 | testA2 | NULL | NULL | NULL | 
| 3 | testA3 | testA3 | NULL | NULL | NULL | 
+------+--------+--------+---------+--------+--------+ 
3 rows in set (0.00 sec) 
+1

Первый пример отрицая 'внешний join' - вы можете двигаться, что критерии к' on' и он должен работать нормально без 'null' проверить. – sgeddes

ответ

3

Почему SQL-запрос с! = 0 не включает значения NULL?

Короткий ответ: Потому что SELECT 0 != NULL возвращает (NULL)

Longer Ответ: Согласно MySQL's documentation

Вы не можете использовать арифметические операторы сравнения, такие как =, < или <> для проверки на NULL.

Если вы хотите включить NULL в вашей Select статей вы должны перевести его в этом арифметическое представление с помощью «IS NULL» или «IFNULL».

Ваш SQL-запрос можно переписать в виде:

SELECT * 
FROM tableA a 
LEFT JOIN tableB b ON a.id = b.join_id 
WHERE 
    IFNULL(b.field1, -1) != 0; 
+2

Или просто используйте MySQL 'NULL'-безопасный оператор сравнения равенства, [' <=> '] (https://dev.mysql.com/doc/en/comparison-operators.html#operator_equal-to) -e.g. 'WHERE NOT b.field1 <=> 0'. – eggyal

+1

Очень приятно, спасибо за информацию. – dgig

1

При использовании внешнего соединения, SQL двигатели представляют собой отсутствие данных в сочетании с использованием наборов нулевых значений. проверки равенства с нулевыми значениями всегда возвращают false.

Рассмотрите: случай, когда null = null, затем 1 else 0 end, это всегда даст 0!

Вы спрашивали: Почему SQL-запрос с! = 0 не включает значения NULL?

В вашем запросе применяется предложение where ПОСЛЕ того, как двигатель генерирует объединенный набор данных.
Пусть А имеют идентификаторы 1,2 и B имеет только 1.

Ваших набор результатов слева присоединиться бы без где положение:

A.ID B.ID 
    1 1 
    2 NULL 

Ваш пункт, где применяется b.field = 0

и вы получите

A.ID B.ID 
    1 1 

Null проверки равенства всегда имеет значение FALSE, так строка 2 исключается и линия 1 сохраняется.

Если вы переместите фильтр в критерии соединения, предел применяется до того, как соединяются таблицы.

SELECT * FROM tableA a 
LEFT JOIN tableB b 
    ON a.id = b.join_id 
    and b.field1 != 0; 

    A.ID B.ID 
    1 1 
    2 NULL 

и поскольку в строке B нет строки для строки 2, вы получаете обе строки.

Как MySQL не считает NULL равным! = 0?

Null - особый случай. Сравнение равенств с нулевым значением всегда будет давать false.

is null, is not null - два метода, которые вы можете использовать, чтобы проверить, является ли значение нулевым.

Возможно, вы также использовали where coalesce(b.field1,1) != 0 для обеспечения возврата 2-й записи. Хотя вам лучше просто перемещать какие-либо фильтры на 2-й стол в левом соединении с критикой join.

+1

Не * строго * правильные сравнения с использованием 'NULL' yield' NULL', а не 'FALSE'. – eggyal

+0

'select case when null = null then 1 when null <> null then 0 else -1 end' Хорошая точка! – xQbert

+0

Жаль, что я не мог согласиться с обоими. Спасибо за подробный ответ. – dgig