Почему SQL не поддерживает "= null" вместо "null"?
Я не спрашиваю , если. Я знаю, что это не так.
Мне любопытно, почему. Я прочитал документы поддержки, такие как о работе с нулями в MySQL, но на самом деле они не дают никаких оснований. Они только повторяют мантру, которую вы должны использовать вместо "null".
Это всегда беспокоило меня. Когда вы выполняете динамический SQL (те редкие времена, когда это нужно сделать), было бы намного проще передать "null" в where where так:
@where = "where GroupId = null"
Это будет простая замена обычной переменной. Вместо этого мы должны использовать if/else блоки для создания таких вещей, как:
if @groupId is null then
@where = "where GroupId is null"
else
@where = "where GroupId = @groupId"
end
В более сложных задачах, это огромная боль в шее. Существует ли конкретная причина, по которой SQL и все основные производители RDBMS этого не допускают? Какой-то конфликт ключевых слов или конфликт значений, которые он создал?
Edit:
Проблема с множеством ответов (на мой взгляд) заключается в том, что каждый настраивает эквивалентность между нулем и "я не знаю, что это за значение". Там огромная разница между этими двумя вещами. Если null означает "там значение, но неизвестно", я бы 100% согласился с тем, что nulls не могут быть равными. Но SQL null не означает этого. Это означает, что существует значение нет. Любые два результата SQL, которые являются нулевыми, не имеют значения. Нет значение не равно неизвестно. Две разные вещи. Это важное различие.
Изменить 2:
Другая проблема, которую я имею, заключается в том, что другие HLL разрешают null = null совершенно нормально и разрешают ее соответствующим образом. В С#, например, null = null возвращает true.
Ответы
Ответ 1
Причина, по которой это по умолчанию, заключается в том, что null
действительно не соответствует null
в бизнес-смысле. Например, если вы присоединились к заказам и клиентам:
select * from orders o join customers c on c.name = o.customer_name
Не было бы большого смысла сопоставлять заказы с неизвестным клиентом с клиентами с неизвестным именем.
Большинство баз данных позволяют настроить это поведение. Например, в SQL Server:
set ansi_nulls on
if null = null
print 'this will not print'
set ansi_nulls off
if null = null
print 'this should print'
Ответ 2
Равенство - это то, что может быть абсолютно определено. Проблема с null
заключается в том, что она по своей сути неизвестна. Если вы следуете таблице истинности для трехзначной логики, null
в сочетании с любым другим значением null
- неизвестно. Запрос SQL "Является ли мое значение равным null?" будет неизвестно каждый раз, даже если значение ввода равно null. Я думаю, что реализация IS NULL
дает понять.
Ответ 3
Это языковая семантика.
Null - это отсутствие значения.
is null
имеет смысл для меня. В нем говорится: "отсутствует ценность" или "неизвестно". Лично я никогда не спрашивал кого-то, если что-то есть, "равное отсутствию ценности".
Ответ 4
Понятие состоит в том, что NULL не является справедливым значением. Это означает отсутствие значения.
Поэтому переменную или столбец можно проверить только, если она IS NULL
, но не если она IS EQUAL TO NULL
.
Как только вы откроете арифметические сравнения, вам, возможно, придется бороться с IS GREATER THAN NULL
или IS LESS THAN OR EQUAL TO NULL
Ответ 5
NULL неизвестно. Это не правда и не ложно, поэтому, когда вы сравниваете что-либо с неизвестным, единственный ответ "неизвестен". Лучше статья о wikipedia http://en.wikipedia.org/wiki/Null_(SQL)
Ответ 6
Я не могу не чувствовать, что вы все еще не удовлетворены ответами, которые были даны до сих пор, поэтому я подумал, что попробую еще один курс. Дайте пример (нет, я не знаю, почему этот конкретный пример пришел мне в голову).
У нас есть таблица для сотрудников, EMP
:
EMP
---
EMPNO GIVENNAME
E0001 Boris
E0002 Chris
E0003 Dave
E0004 Steve
E0005 Tony
И по какой-то причудливой причине мы отслеживаем, какие цветные штаны каждый сотрудник выбирает носить в определенный день (TROUS
):
TROUS
-----
EMPNO DATE COLOUR
E0001 20110806 Brown
E0002 20110806 Blue
E0003 20110806 Black
E0004 20110806 Brown
E0005 20110806 Black
E0001 20110807 Black
E0003 20110807 Black
E0004 20110807 Grey
Я мог бы продолжить. Мы пишем запрос, где мы хотим узнать имя каждого сотрудника и какие цветные штаны у них были 7 августа:
SELECT e.GIVENNAME,t.COLOUR
FROM
EMP e
LEFT JOIN
TROUS t
ON
e.EMPNO = t.EMPNO and
t.DATE = '20110807'
И получим набор результатов:
GIVENNAME COLOUR
Chris NULL
Steve Grey
Dave Black
Boris Black
Tony NULL
Теперь этот набор результатов может быть в представлении, или CTE, или что-то еще, и мы, возможно, захотим продолжить задавать вопросы об этих результатах, используя SQL. Какие могут быть некоторые из этих вопросов?
-
Были ли в тот день Дейва и Бориса в темных цветных штанах? (Да, черный == Черный)
-
Были ли Дэйв и Стив в тех же цветах в тот день? (Нет, Черный!= Серый)
-
Были ли в тот день Борис и Тони в одних и тех же цветных брюках? (Неизвестно - мы пытаемся сравнить с NULL, и мы следуем правилам SQL)
-
Были ли Борис и Тони не в тех же цветных штанах в этот день? (Неизвестно - мы снова сравниваем с NULL, и мы следуем правилам SQL)
-
Были ли в тот день Криса и Тони в тех же цветных брюках? (Неизвестно)
Обратите внимание, что вы уже знаете о конкретных механизмах (например, IS NULL
), чтобы заставить нужные вам результаты, если вы разработали базу данных, чтобы никогда не использовать NULL в качестве маркера для отсутствия информации.
Но в SQL NULL получили две роли (по крайней мере) - чтобы отметить неприменимую информацию (возможно, у нас есть полная информация в базе данных, а Крис и Тони не появились на работу в тот день или не сделали этого "ношу брюки" ) и отметить недостающую информацию (в этот день появился Крис, у нас просто нет информации, записанной в базе данных в настоящее время)
Если вы используете NULL
чисто как маркер неприменимой информации, я предполагаю, что вы избегаете таких конструкций, как внешние соединения.
Мне интересно, что вы добавили NaN
в комментарии к другим ответам, не заметив, что NaN
и (SQL) NULL
имеют много общего. Самое большое различие между ними заключается в том, что NULL
предназначен для использования по всей системе, независимо от того, какой тип данных задействован.
Самая большая проблема заключается в том, что вы решили, что NULL имеет одно значение во всех языках программирования, и вы, кажется, чувствуете, что SQL нарушил это значение. Фактически, нуль на разных языках часто имеет тонко разные значения. На некоторых языках это синоним 0. В других нет, поэтому сравнение 0==null
преуспеет в одних и не удастся другим. Вы упомянули VB, но VB (при условии, что вы говорите, версии .NET) не имеет значения null. Он имеет Nothing
, что опять-таки немного отличается (это эквивалентно в большинстве случаев конструкции С# default(T)
).
Ответ 7
Потому что в ANSI SQL значение null означает "неизвестно", что не является значением. Таким образом, он ничем не равен; вы можете просто оценить состояние значения (известное или неизвестное).
Ответ 8
а. Нуль - это не "недостаток значения"
б. Null не является "пустым"
с. Null не является "неустановленным значением"
Все вышесказанное и ни одно из вышеперечисленных.
По техническим правам NULL является "неизвестным значением". Однако, как и неинициализированные указатели в C/С++, вы действительно не знаете, на что вы указываете. В базах данных они выделяют пространство, но не инициализируют значение в этом пространстве.
Итак, это "пустое" пространство в том смысле, что оно не инициализировано. Если вы установите значение NULL, исходное значение останется в этом месте хранения. Если это была изначально пустая строка (например), она останется той.
Это "недостаток значения" в том, что он не был настроен на то, что база данных считает допустимым.
Это "неустановленное значение" в том, что если пространство было просто выделено, значение, которое там никогда не было установлено.
"Неизвестный" - это самое близкое, что мы действительно можем узнать, чего ожидать, когда исследуем NULL.
Из-за этого, если мы попытаемся сравнить это "неизвестное" значение, мы получим сравнение, которое
a) может быть или не быть действительным
b) может или не может быть ожидаемый результат
c) может или не может сбой базы данных.
Итак, системы СУБД (давно) решили, что даже не имеет смысла использовать равенство, когда дело доходит до NULL.
Поэтому "= null" не имеет смысла.
Ответ 9
В дополнение ко всему, что уже было сказано, я хочу подчеркнуть, что то, что вы пишете в своей первой строке, неверно. SQL поддерживает синтаксис "= NULL", но имеет другую семантику, чем "IS NULL" - как видно из самой части документации, с которой вы связаны.
Ответ 10
Я согласен с OP, что
where column_name = null
должен быть синтаксическим сахаром для
where column_name is null
Однако я понимаю, почему создатели SQL хотели сделать различие. В трехзначной логике (ИМО это неправильное обозначение) предикат может возвращать два значения (истинные или ложные) ИЛИ неизвестные, что технически не является значением, а просто способ сказать "мы не знаем, какое из двух значений это является". Подумайте о следующем предикате в терминах трехзначной логики:
A == B
Этот предикат проверяет, является ли A равным B. Здесь выглядит таблица истинности:
T U F
-----
T | T U F
U | U U U
F | F U T
Если A или B неизвестны, сам предикат всегда возвращает неизвестный, независимо от того, является ли другой истиной или ложной или неизвестной.
В SQL значение null является синонимом неизвестного. Итак, предикат SQL
column_name = null
проверяет, равно ли значение column_name чему-то, чье значение неизвестно, и возвращает неизвестно независимо от того, является ли column_name истинным или ложным или неизвестным или что-то еще, точно так же, как в трехзначной логике выше. Операции SQL DML ограничены работой в строках, для которых предикат в предложении where возвращает true, игнорируя строки, для которых предикат возвращает false или неизвестно. Поэтому "where column_name = null" не работает ни в одной строке.
Ответ 11
NULL не равен NULL. Он не может равняться NULL. Для них не имеет смысла быть равными.
Несколько способов подумать об этом:
-
Представьте базу данных контактов, содержащую такие поля, как FirstName
, LastName
, DateOfBirth
и HairColor
. Если бы я искал записи WHERE DateOfBirth = HairColor
, должен ли он когда-либо соответствовать чему-либо? Что, если кто-то DateOfBirth
был NULL, а их HairColor
тоже? Неизвестный цвет волос не равен никому неизвестному.
-
Позвольте присоединиться к таблице контактов с таблицами покупок и продуктов. Скажем, я хочу найти все случаи, когда клиент купил парик, который был того же цвета, что и их собственные волосы. Поэтому я запрашиваю WHERE contacts.HairColor = product.WigColor
. Должен ли я получать совпадения между каждым клиентом, я не знаю цвета волос и продуктов, у которых нет WigColor
? Нет, это другое дело.
-
Давайте рассмотрим, что NULL - это другое слово для неизвестного. Каков результат ('Smith' = NULL)
? Ответ не является ложным, он неизвестен. Неизвестно, это неверно, поэтому оно ведет себя как ложное. Каков результат (NULL = NULL)
? Ответ также неизвестен, поэтому также эффективно ложный. (Это также связано с тем, что объединение строки со значением NULL приводит к тому, что вся строка становится NULL - результат действительно неизвестен.)
Ответ 12
Почему вы не используете функцию isnull?
@where = "where GroupId = "+ isnull(@groupId,"null")