MySQL mystery: нулевое значение не отличается от ненулевой строки - PullRequest
3 голосов
/ 04 августа 2010

Почему этот запрос возвращает 0 строк?

select t.f1, t.f2
from (select null f1, 'a' f2 from dual) t
where t.f1<>t.f2;

Это искаженная версия сложного запроса, который у меня есть. Я хочу сравнить две таблицы, содержащие данные, относящиеся к одному, и выбрать те строки, которые содержат разные значения для определенных полей. Но также может быть случай, когда в одной из таблиц отсутствует одна строка. LEFT JOIN правильно возвращает нулевые значения для этих строк, но затем предложение WHERE неправильно (или неожиданно) отфильтровывает эти строки.

Почему, в этом случае, 'null' НЕ РАЗНИМАЕТСЯ ни на одно ненулевое значение (например, 'a')? Что сводит меня с ума, так это то, что это

select t.f1, t.f2
from (select null f1, 'a' f2 from dual) t;

возвращает 1 строку (как я и ожидал), но это

select t.f1, t.f2
from (select null f1, 'a' f2 from dual) t
where t.f1=t.f2;

возвращает 0 строк !! Значит, ноль не равен «а» и ноль не отличается от «а» !!

Пожалуйста ... Кто-нибудь может это объяснить?

Ответы [ 5 ]

5 голосов
/ 04 августа 2010

Точно. NULL представляет неизвестное значение, а не какое-либо конкретное значение (оно не совпадает с NULL в C или nil в Ruby и т. Д.) В SQL, если вы сравниваете что-то с неизвестным значением, результат Также неизвестно. И вы не получите строки, где WHERE условие неизвестно.

Попробуйте это:

SELECT NULL <> 2;

и вы увидите NULL как результат.

Попробуйте это:

SELECT * FROM t WHERE NULL;

и никаких строк не будет, даже если таблица t огромна.

Если вам действительно нужно то, что вы сказали, что хотели (а я не защищаю это), вы можете сделать что-то вроде этого:

SELECT T.f1, T.f2
FROM (SELECT NULL f1, 'a' f2) T
WHERE ((T.f1 IS NULL OR T.f2 IS NULL)
    AND (T.f1 IS NOT NULL OR T.f2 IS NOT NULL))
    OR T.f1 <> T.f2
3 голосов
/ 04 августа 2010

Концепция NULL является распространенным источником путаницы для новичков в SQL, которые часто думают, что NULL рассматривается как другие значения.

Это не тот случай. Концептуально, NULL означает «пропущенное неизвестное значение», и поэтому оно трактуется совсем по-другому

То, что вы видите, довольно легко объяснить. Рассмотрим следующий пример:

CREATE TABLE mytb (id int, value int);

INSERT INTO mytb VALUES (1, 100);
INSERT INTO mytb VALUES (2, 200);
INSERT INTO mytb VALUES (3, NULL);
INSERT INTO mytb VALUES (4, 400);

Вышеуказанное означает, что для строки с id = 3 значение равно «unknown». Это может быть 300, или 100, или что-то еще.

Поэтому, когда вы запрашиваете следующее:

SELECT * FROM mytb WHERE value <> 100;
+------+-------+
| id   | value |
+------+-------+
|    2 |   200 |
|    4 |   400 |
+------+-------+
2 rows in set (0.00 sec)

Строка с id = 3 не возвращается, потому что NULL <> 100 возвращает «неизвестно». Мы не знаем, имеет ли строка id = 3 значение 100, поэтому выражение не возвращает true. Я тоже не верну false. Возвращает «неизвестно» (NULL).

Условие предложения WHERE может быть выполнено только тогда, когда выражение true. Когда вы сравниваете что-то с NULL, выражение никогда не может быть истинным. Это будет «неизвестно».

1 голос
/ 04 августа 2010

SQL NULL не работает так, как вы хотели бы: http://en.wikipedia.org/wiki/Sql_null

Короче говоря, NULL = NULL не соответствует действительностиNULL <> NULL не соответствует действительности.NULL <> 1 не соответствует действительности.И пр.

0 голосов
/ 04 августа 2010

Значение NULL - ничто, оно не может быть равно или не равно чему-либо.Если вы хотите проверить, является ли ваше значение пустым - используйте выражение «IS NULL»:

select t.f1, t.f2
from (select null f1, 'a' f2 from dual) t
where t.f1 IS NULL

Если вы хотите проверить, равны ли ваши значения или нет - вы можете использовать COALESCE функция на обнуляемых столбцах:

select t.f1, t.f2
from (select null f1, 'a' f2 from dual) t
where COALESCE(t.f1, '')<>COALESCE(t.f2, '');
0 голосов
/ 04 августа 2010

Попробуйте выполнить этот запрос:

   select * from dual where NULL = NULL

Возвращает 0 строк.Это связано с тем, что для сравнения значения с нулем необходимо выполнить IS NULL или IS NOT NULL, в противном случае будет возвращено false .

...