Почему SQL не поддерживает "= null" вместо "is null"? - PullRequest
25 голосов
/ 16 августа 2011

Я не спрашиваю , если это так.Я знаю, что это не так.

Мне любопытно узнать причину.Я читал документы поддержки, такие как этот по работе с нулями в MySQL , но они на самом деле не дают никаких оснований.Они только повторяют мантру, которую вы должны использовать вместо «ноль».

Это всегда беспокоило меня.При выполнении динамического SQL (в тех редких случаях, когда это нужно делать) было бы намного проще передать выражение «ноль» в выражение where, например, так:

@where = "where GroupId = null"

Что будет простой заменой обычногопеременная.Вместо этого мы должны использовать блоки if / else для выполнения таких вещей, как:

if @groupId is null then
     @where = "where GroupId is null"
else
     @where = "where GroupId = @groupId"
end

В более крупных и сложных запросах это огромная боль в шее.Есть ли конкретная причина, по которой SQL и все основные поставщики РСУБД не допускают этого?Какой-то конфликт ключевых слов или конфликта значений, который он может создать?

Редактировать:

Проблема с множеством ответов (на мой взгляд) заключается в том, что всеустановка эквивалентности между нулем и «я не знаю, каково значение».Между этими двумя вещами есть огромная разница.Если ноль означает «есть значение, но оно неизвестно», я бы на 100% согласился, что нули не могут быть равными.Но SQL-ноль не означает это.Это означает, что значение отсутствует .Любые два результата SQL, которые являются нулевыми, не имеют значения. Нет значение не равно неизвестно значение.Две разные вещи.Это важное различие.

Редактировать 2:

Другая проблема, с которой я столкнулся, заключается в том, что другие HLL-файлы позволяют null = null совершенно нормально и разрешают его соответствующим образом.Например, в C # null = null возвращает true.

Ответы [ 12 ]

21 голосов
/ 16 августа 2011

Причина, по которой он отключен по умолчанию, заключается в том, что 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'
9 голосов
/ 16 августа 2011

Равенство - это то, что может быть абсолютно определено. Проблема с null в том, что она по сути неизвестна. Если вы следуете таблице истинности для трехзначной логики, null в сочетании с любым другим значением будет null - неизвестно. Запрашиваемая SQL "Является ли мое значение равно ноль?" будет неизвестен каждый раз, даже если ввод будет нулевым . Я думаю, что реализация IS NULL проясняет.

5 голосов
/ 16 августа 2011

Это языковая семантика.

Ноль - это отсутствие значения.

is null имеет смысл для меня. Он говорит, «не хватает значения» или «неизвестно». Лично я никогда не спрашивал кого-то, является ли что-то «равным отсутствию ценности».

4 голосов
/ 17 августа 2011

Я не могу не чувствовать, что вы все еще не удовлетворены ответами, которые были даны до сих пор, поэтому я подумал, что попробую еще один прием. Давайте рассмотрим пример (нет, я понятия не имею, почему этот конкретный пример пришел мне в голову).

У нас есть стол для сотрудников, 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. Какими могут быть некоторые из этих вопросов?

  1. Дэйв и Борис были одеты в брюки того же цвета в тот день? (Да, Черный == Черный)

  2. Дэйв и Стив носили в тот же день брюки одного цвета? (Нет, черный! = Серый)

  3. В этот день Борис и Тони были одеты в брюки одного цвета? (Неизвестно - мы пытаемся сравнить с NULL и следуем правилам SQL)

  4. Разве Борис и Тони не были одеты в брюки того же цвета в тот день? (Неизвестно - мы снова сравниваем с NULL и следуем правилам SQL)

  5. В этот день Крис и Тони были одеты в брюки одного цвета? (Неизвестно)

Обратите внимание, что вы уже знаете о конкретных механизмах (например, IS NULL) для форсирования желаемых результатов, если вы разработали базу данных так, чтобы никогда не использовать NULL в качестве маркера для недостающей информации.

Но в SQL NULL было дано две роли (по крайней мере) - чтобы пометить неприменимую информацию (возможно, у нас есть полная информация в базе данных, а Крис и Тони не пришли на работу в тот день, или сделали, но не были не в брюках) и для обозначения недостающей информации (Крис появился в тот день, у нас просто нет информации, записанной в базе данных в это время)

Если вы используете NULL исключительно как маркер неприменимой информации, я предполагаю, что вы избегаете таких конструкций, как внешние объединения.


Мне интересно, что вы упомянули NaN в комментариях к другим ответам, не видя, что NaN и (SQL) NULL имеют много общего. Самое большое различие между ними заключается в том, что NULL предназначен для использования в системе независимо от типа данных.

Похоже, ваша самая большая проблема заключается в том, что вы решили, что NULL имеет единое значение для всех языков программирования, и вам кажется, что SQL нарушил это значение. На самом деле, ноль в разных языках часто имеет несколько разные значения. В некоторых языках это синоним 0. В других нет, поэтому сравнение 0==null в одних будет успешным, а в других - неудачным. Вы упомянули VB, но у VB (если вы говорите о версиях .NET) нет нуля. Он имеет Nothing, что опять-таки немного отличается (это в большинстве случаев эквивалентно конструкции C # default(T)).

3 голосов
/ 16 августа 2011

NULL неизвестно. Это не правда и не ложь, поэтому, когда вы сравниваете что-то с неизвестным, единственный ответ - «неизвестно». Гораздо лучшая статья в Википедии http://en.wikipedia.org/wiki/Null_(SQL)

3 голосов
/ 16 августа 2011

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

Следовательно, переменная или столбец могут быть проверены, только если они IS NULL, но не если они IS EQUAL TO NULL.

После того, как вы откроете арифметические сравнения, вам, возможно, придется бороться с IS GREATER THAN NULL или IS LESS THAN OR EQUAL TO NULL

2 голосов
/ 20 августа 2011

а.Нуль - это не «отсутствие значения»

b.Null не является «пустым»

c.Null не является «неустановленным значением»

Это все из перечисленного и ничего из вышеперечисленного.

По техническим правам, NULL является «неизвестным значением».Однако, как и неинициализированные указатели в C / C ++, вы на самом деле не знаете, на что вы указываете.В базах данных они выделяют пространство, но не инициализируют значение в этом пространстве.

Таким образом, это «пустое» пространство в том смысле, что оно не инициализировано.Если вы установите значение NULL, исходное значение останется в этом месте хранения.Если изначально это была пустая строка (например), она останется таковой.

Это «отсутствие значения» в том факте, что для него не установлено значение, которое база данных считает допустимым значением.

Это «неустановленное значение» в том смысле, что если пространство было только что выделено, то значение, которое там никогда не было установлено.

«Неизвестно» - самое близкое, что мы действительно можем узнатьчто ожидать, когда мы исследуем NULL.


Из-за этого, если мы попытаемся сравнить это «неизвестное» значение, мы получим сравнение, которое

a) может или может бытьне может быть действительным

b) может или не может иметь ожидаемый результат

c) может или не может сбой базы данных.

Итак, системы СУБД (давно) решил, что не имеет смысла использовать равенство, когда дело доходит до NULL.

Следовательно, "= null" не имеет смысла.

2 голосов
/ 16 августа 2011

Потому что в ANSI SQL null означает «неизвестно», что не является значением. Как таковое, оно ничему не равно Вы можете просто оценить состояние значения (известного или неизвестного).

1 голос
/ 22 октября 2014

Я согласен с ФП, что

where column_name = null

должно быть синтаксический сахар для

where column_name is null

Однако я понимаю, почему создатели SQL хотели провести различие. В трехзначной логике (IMO это неверное выражение) предикат может возвращать два значения ( true или false ) ИЛИ unknown , что технически не является значением но просто способ сказать «мы не знаем, какое из двух значений это». Подумайте о следующем предикате с точки зрения трехзначной логики:

A == B

Этот предикат проверяет, равен ли A значению B. Вот как выглядит таблица истинности:

    T U F
    -----
T | T U F
U | U U U
F | F U T

Если A или B неизвестны, сам предикат всегда возвращает неизвестное, независимо от того, является ли другой истинным, ложным или неизвестным.

В SQL null является синонимом unknown . Итак, предикат SQL

column_name = null

проверяет, равно ли значение column_name чему-либо, чье значение неизвестно, и возвращает неизвестное, независимо от того, является ли column_name истинным, ложным, неизвестным или чем-то еще, как в трехзначной логике выше. Операции SQL DML ограничены работой со строками, для которых предикат в предложении where возвращает true, игнорируя строки, для которых предикат возвращает false или unknown. Вот почему «where column_name = null» не работает ни с какими строками.

1 голос
/ 16 августа 2011

В дополнение ко всему, что уже было сказано, я хочу подчеркнуть, что то, что вы пишете в первой строке, неверно. SQL поддерживает синтаксис «= NULL», но имеет семантику, отличную от «IS NULL» - как видно из самой документации, с которой вы связаны.

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