SQL: пустая строка против значения NULL

72

Я знаю, что эта тема немного противоречива, и в Интернете много разных статей / мнений. К сожалению, большинство из них предполагают, что человек не знает, в чем разница между NULL и пустой строкой. Таким образом, они рассказывают истории об удивительных результатах с объединениями / агрегатами и обычно делают более продвинутые уроки SQL. Делая это, они абсолютно упускают из виду весь смысл и поэтому бесполезны для меня. Поэтому, надеюсь, этот вопрос и все ответы будут продвигать тему немного вперед.

Предположим, у меня есть таблица с личной информацией (имя, рождение и т. Д.), Где один из столбцов - это адрес электронной почты с типом varchar. Мы предполагаем, что по некоторым причинам некоторые люди могут не захотеть предоставлять адрес электронной почты. При вставке таких данных (без электронной почты) в таблицу доступны два варианта: установить для ячейки значение NULL или установить для нее пустую строку (''). Давайте предположим, что мне известны все технические последствия выбора одного решения вместо другого, и я могу создавать правильные запросы SQL для любого сценария. Проблема в том, что даже когда оба значения отличаются на техническом уровне, они одинаковы на логическом уровне. Посмотрев на NULL и «», я пришел к единственному выводу: я не знаю адреса электронной почты этого парня. Кроме того, как бы я ни старался, Я не смог отправить электронное письмо, используя NULL или пустую строку, поэтому, очевидно, большинство SMTP-серверов согласны с моей логикой. Поэтому я склонен использовать NULL там, где я не знаю значения и считаю пустую строку плохой вещью.

После нескольких интенсивных бесед с коллегами я пришел с двумя вопросами:

  1. Прав ли я, полагая, что использование пустой строки для неизвестного значения приводит к тому, что база данных «лжет» о фактах? Чтобы быть более точным: используя представление SQL о том, что является ценностью, а что нет, я мог бы прийти к выводу: у нас есть адрес электронной почты, просто обнаружив, что он не является нулевым. Но потом, когда я попытаюсь отправить электронное письмо, я приду к противоречивому выводу: нет, у нас нет адреса электронной почты, потому что база данных @! # $ Должна была лгать!

  2. Существует ли какой-либо логический сценарий, в котором пустая строка '' могла бы быть таким хорошим носителем важной информации (помимо значения и отсутствия значения), которую было бы проблематичным / неэффективным хранить любым другим способом (например, дополнительным столбцом). Я видел много постов, утверждающих, что иногда полезно использовать пустую строку вместе с реальными значениями и значениями NULL, но до сих пор не видел сценарий, который был бы логичным (с точки зрения дизайна SQL / DB).

PS У некоторых людей возникнет соблазн ответить, что это вопрос личного вкуса. Я не согласна Для меня это дизайнерское решение с важными последствиями. Поэтому я хотел бы увидеть ответы, в которых мнение об этом подкреплено какими-то логическими и / или техническими причинами.

Яцек Прусия
источник
11
Знаете ли вы, что в Oracle пустая строка имеет значение NULL?
user281377 30.12.10
8
@ammoQ: Oracle обрабатывает строки нулевой длины нестандартно. К тому же ''даже в Oracle это не так, как NULL. Например, присвоение CHAR(1)столбцу значения ''приведет к ' '(то есть к пробелу), а не к NULL. Кроме того, если бы Яцек использовал Oracle, этот вопрос, вероятно, даже не поднимался бы :-)
Дин Хардинг,
2
Дин: Вы правы в отношении примера char (1), но это еще один WTF, поскольку он '' IS NULLоценивается trueв PL / SQL.
user281377 30.12.10
«Прав ли я, полагая, что использование пустой строки для неизвестного значения приводит к тому, что база данных« лжет »о фактах?» если ваши бизнес-пользователи не заботятся о неизвестном или пустом, имеет ли значение ложь?
Энди
Если вы должны пойти по пути использования строки ... пожалуйста, убедитесь, что она пуста. Ради всех разработчиков, не позволяйте строке с пробелом в ней представлять ваше неизвестное значение. Умоляю вас.
Airn5475

Ответы:

83

Я бы сказал, что NULLэто правильный выбор для «нет адреса электронной почты». Есть много «недействительных» адресов электронной почты, и «» (пустая строка) - только один. Например, «foo» не является действительным адресом электронной почты, «a @ b @ c» недопустим и так далее. Так что просто потому, что «» не является действительным адресом электронной почты, нет причин использовать его в качестве значения «нет адреса электронной почты».

Я думаю, что вы правы, говоря, что «» - это неправильный способ сказать «у меня нет значения для этого столбца». «» Представляет значение.

Примером того, где "" может быть допустимым значением, NULLможет быть отчество человека. Не у каждого есть отчество, поэтому нужно различать «без отчества» («» - пустая строка) и «я не знаю, есть у этого отчества второе имя» ( NULL). Вероятно, есть много других примеров, когда пустая строка все еще является допустимым значением для столбца.

Дин Хардинг
источник
5
Полностью согласен. NULL существует по причине. ВЫБЕРИТЕ COUNT (*) ИЗ ВАШЕЙ ТАБЛИЦЫ, ГДЕ ЭЛЕКТРОННАЯ ПОЧТА [NOT] NULL - это способ сделать это, а не сравнение строк, которое, как правило, будет медленнее (даже для пустых строк, я полагаю, но я не уверен в этом :).
LudoMC
5
Я думаю, NULLэто не означает, что адрес электронной почты отсутствует, я думаю, что это означает, что адрес электронной почты в настоящее время неизвестен, не существует или его невозможно заполнить по другим причинам. К счастью, вероятно, нет ситуации, когда кто-то хотел бы хранить в базе данных информацию о людях, которые действительно не имеют и не планируют иметь какой-либо адрес электронной почты, в противном случае, вероятно, потребуется отдельное логическое поле.
Алексей
9
@Alexey - NULL означает, что значения нет. Как уже отмечали другие, пустая строка является значением.
Ramhound
3
@Ramhound, я согласен, что пустая строка является значением, и что NULL неопределенно означает «нет значения». Я только что объяснил свою интерпретацию «нет ценности». На мой взгляд, это не то же самое, что "человек не открыл ни одной учетной записи электронной почты". Это скорее "адрес электронной почты не зарегистрирован для этого человека".
Алексей
5
@Ramhound NULL означает, что значения нет. Человек без отчества там не имеет значения. Следовательно, NULL следует использовать и в среднем начальном столбце ... Что полностью противоположно аргументу, представленному в этом ответе.
Иската,
41

Соглашаясь с приведенными выше комментариями, я бы добавил этот аргумент в качестве основной мотивации:

  1. Для любого программиста, просматривающего базу данных, очевидно, что поле, помеченное как NULL, является необязательным. (т.е. запись не требует данных для этого столбца)
  2. Если вы отметите поле NOT NULL, любой программист должен интуитивно предположить, что это поле Обязательное.
  3. В поле, которое допускает нулевые значения, программисты должны ожидать увидеть нулевые значения, а не пустые строки.

Для самодокументируемого интуитивного кодирования используйте NULL вместо пустых строк.

colinbashbash
источник
4
+1 Это аргумент «наименьшего удивления» по отношению к разработчикам против пустых строк. Ни один разработчик, который придет позже, никогда бы не ожидал, что пустые строки будут использоваться для обозначения «нет адреса электронной почты».
Томас
6

В вашем примере, если это значение прямо из веб-поля - я бы использовал пустую строку. Если пользователь может указать, что он не хочет предоставлять электронную почту, или может удалить ее - тогда NULL.

Вот ссылка с точками, которые вы могли бы рассмотреть: https://stackoverflow.com/questions/405909/null-vs-empty-when-dealing-with-user-input/405945#405945

--- отредактировано (в ответ на комментарий Томаса) ---

Базы данных не живут без приложений, которые их используют. Определение NULL или '' не имеет значения, если приложение не может использовать его должным образом.

Рассмотрим один пример, когда пользователь заполняет форму LONG и нажимает Enter, которая отправляет постоянный запрос на сервер. Он может быть в середине ввода своего электронного письма. Скорее всего, вы хотите сохранить все, что он имеет в поле электронной почты, чтобы потом он мог закончить это. Что если он введет только один символ? Что если он введет один символ и затем удалит его? Когда электронная почта не требуется, иногда пользователи хотят ее удалить: самый простой способ просто очистить поле. Также в случае, когда электронная почта не требуется, стоит проверить ее перед отправкой.

Другой пример: пользователь предоставляет электронную почту как spamto @ [bigcompany] .com - в этом случае нет необходимости отправлять электронную почту, даже если она существует и действительна (и может даже существовать). Отправка одного такого может быть дешевой, но если для ежедневных подписок есть 10 000 пользователей с такими электронными письмами, то такая проверка может сэкономить много времени.

Константин Петрухнов
источник
7
-1. Является ли база данных движущей силой сайта или нет, не имеет значения. Проектирование баз данных - это другой мир, чем веб-дизайн. База данных должна быть разработана для сбора фактов о бизнес-сфере независимо от интерфейса, используемого для записи в нее. По вашей логике, вы должны использовать нули, если по совпадению первое приложение является исполняемым файлом? Что произойдет, если первое приложение является веб-приложением, а следующее приложение является мобильным приложением? Разработка базы данных для сбора фактов с использованием правил нормализации и разработка веб-сайта для записи в нее.
Томас
Я рад, что вы узнали, как писать и комментировать этот сайт :) Я все еще считаю, что БД должна поддерживать приложение, которое его использует. Проверьте мой отредактированный ответ.
Константин Петрухнов
4
Базы данных не живут без приложений, которые их используют. По моему опыту, это просто неправда и близорукость. Почти всегда база данных используется вне приложения, для которого она была разработана. Как правило, базы данных живут дольше, чем приложения, для которых они были созданы. Базы данных должны быть предназначены для сбора фактов о бизнесе, а пользовательский интерфейс должен быть построен для чтения и записи в базу данных, а не наоборот. Реляционный дизайн - это совершенно другое мышление, чем дизайн приложений.
Томас
2
Примеры , когда база данных не используется исключительно в оригинальной заявке: отчеты, интеграция с другими системами.
Томас
1
Как указал Томас, базы данных могут и часто используются более чем одним приложением, что добавляет веса идее поддержания чистоты данных вашей базы данных. Если вы не хотите / не можете обрабатывать значения NULL в своем приложении, вы можете просто заменить их своими «магическими значениями» (хорошее описание Thomas) на уровне доступа к данным. Таким образом, любые будущие приложения, которые хотят получить доступ к БД, не должны знать о магических ценностях исходных приложений / соответствовать им.
Бендемес
5

Я думаю, что ответ Дина Хардингса охватывает это действительно хорошо. Тем не менее, я хотел бы отметить, что, говоря о пустых строках и пустых строках на уровне БД, вы должны подумать о других ваших типах данных. Будете ли вы хранить минимальную дату, когда дата не указана? или -1, когда int не указан? Сохранение значения, когда у вас нет значения, означает, что вам придется отслеживать весь диапазон не значений. По крайней мере один для каждого типа данных (возможно, больше, когда вы получаете случаи, когда -1 - фактическое значение, поэтому вам нужно иметь какую-то альтернативу и т. Д.). Если вам нужно / вы хотите сделать что-то «вычурное» на уровне приложений, это одно, но не нужно загрязнять ваши данные.

bendemes
источник
2
+1 - это то, что я называю «магическим решением». Мы должны придумать магическое значение для каждого типа данных, чтобы представить отсутствие значения. Кроме того, в некоторых столбцах общее магическое значение является или становится допустимым значением, и поэтому необходимо новое магическое значение.
Томас
5

К сожалению, Oracle перепутал представление строки VARCHAR нулевой длины с представлением NULL. Они оба представлены внутри одним байтом со значением ноль. Это делает обсуждение намного сложнее.

Большая путаница вокруг NULL сосредоточена вокруг трехзначной логики . Рассмотрим следующий псевдокод:

if ZIPCODE = NULL
    print "ZIPCODE is NULL"
else if ZIPCODE <> NULL
    print "ZIPCODE is not NULL"
else print "Something unknown has happened"

Вы не ожидаете третьего сообщения, но это то, что вы получите при трехзначной логике. Три ценная логика ведет людей к многочисленным ошибкам.

Еще одним источником путаницы является вывод из отсутствия данных, например вывод из собаки, которая не лаяла ночью. Часто эти выводы не были тем, что автор NULL намеревался cnvey.

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

Также имейте в виду, что даже если вы полностью избегаете NULLS в хранимых данных (шестая нормальная форма), если вы делаете какие-либо внешние объединения, вам все равно придется справляться с NULLS.

Уолтер Митти
источник
4

Используйте Null.

Нет никакого смысла хранить значение '', когда подойдет просто сделать поле в таблице nullable. Это делает запросы более очевидными.

Какой SQL-запрос более очевиден и удобочитаем, если вы хотите найти пользователей с адресом электронной почты?

  1. SELECT * FROM Users WHERE email_address != ''

  2. SELECT * FROM Users WHERE email_address IS NOT NULL

  3. SELECT * FROM Users WHERE email_address != '' and email_address IS NOT NULL

Я бы сказал, 2 есть. Хотя 3 более надежна в тех случаях, когда хранятся плохие данные.

В случае адреса электронной почты в форме, который является необязательным, он также должен быть отражен в таблице. В SQL это пустое поле, что означает, что оно не известно.

Я не могу думать о какой-либо разумной коммерческой ценности для хранения пустой строки в таблице, кроме просто плохого дизайна. Это похоже на хранение строкового значения «NULL» или «BLANK», и когда разработчики предполагают, что это пустая или пустая строка. Для меня это плохой дизайн. Зачем хранить это, когда есть NULL?

Просто используйте NULL, и вы сделаете всех чуть более счастливыми.

БОЛЬШЕ ИНФОРМАЦИИ:

SQL использует трехзначную логическую систему: True, False и Unknown.

Для лучшего и более подробного объяснения я рекомендую разработчикам прочитать: SQL Queries - за пределами TRUE и FALSE .

Spong
источник
3

для конкретного технического вопроса проблема не пустая, а пустая строка, это ошибка проверки . Пустая строка не является действительным адресом электронной почты!

на философский вопрос ответ аналогичен: подтвердите свои данные. Если пустая строка является допустимым значением для рассматриваемого поля, то ожидайте его и код для него; если нет, используйте ноль.

Пустая строка будет правильным вводом для ответа на вопрос: что пантомима сказала жирафу?

Стивен А. Лоу
источник
Даже при самых лучших намерениях в мире валидация может не решить эту проблему - ему, возможно, все же придется использовать метод, работающий со строками, где все столбцы должны быть снабжены каким-либо значением. В таком случае останется вопрос - какое значение использовать, когда нет значения? И ответ, конечно, будет: значение, которое указывает на отсутствие значения. В БД это обычно NULL.
Jmoreno
2

Я мог бы подумать о причине наличия NULL и пустой строки:

  • У вас есть действующие адреса электронной почты: me@example.com
  • У вас их нет (и, вероятно, стоит попросить): NULL
  • Вы знаете, что у этого человека нет адреса электронной почты: Empty String.

Однако я не рекомендовал бы это и использовал бы отдельное поле для того, чтобы спросить, знаете ли вы, что ни один не существует.

завивать волосы щипцами
источник
1

Насколько я понимаю, вопрос в том, какие интерпретации NULL и пустой строки следует выбирать. Это зависит от того , сколько состояний particualar поле может быть.

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

apoorv020
источник
1

Ну, в принципе, на логическом уровне нет разницы между «недопустимым» значением и «отсутствием пользовательского ввода», в большинстве случаев это просто «особые случаи». Ошибка в случае.

Значение null занимает дополнительное пространство: ceil (columns_with_null / 8) в байтах на строку.

Пустая ячейка и ноль - оба способа пометить что-то не так / должны быть по умолчанию. Зачем вам нужно 2 "неправильных" состояния? Зачем использовать NULL, если они занимают дополнительное место и означают то же самое, что и пустые строки? Это просто внесет путаницу и избыточность, когда у вас есть две вещи, которые означают (что может означать) абсолютно одно и то же, легко забыть, что вы должны использовать NULL вместо пустых строк (если, например, пользователь пропустил некоторые поля).

И ваши данные могут стать беспорядком. В идеальном мире вы бы сказали, что «данные будут всегда правильными, и я буду помнить» ... но когда люди должны работать в команде, а не все точно на вашем уровне, нередко видеть ГДЕ (аа. xx <> '' И bb.zz НЕ НУЛЬ)

Поэтому вместо того, чтобы исправлять членов моей команды каждый день, я просто применяю простое правило. Нет нулевых значений, НИКОГДА!

Подсчет NON-NULL значений происходит быстрее ... простой вопрос: зачем вам это нужно?

Slawek
источник
Я смутно припоминаю, что где-то читал, что использование NULL на самом деле является затратой (как с точки зрения вычислений, так и хранения) для базы данных. Итак, хороший момент в формулировании этой формулы.
Яцек Прусия
Не забывайте, что VARCHARстолбцу потребуется не менее 1 байта для хранения длины строки, даже если она равна нулю.
Ден04
Пустая ячейка и ноль - оба способа пометить что-то не так . Не правда. Ноль - это способ указать на отсутствие значения. Бьюсь об заклад, большинство СУБД используют битовый массив в каждой строке, чтобы указать, какие столбцы являются нулевыми. Таким образом, дополнительное пространство настолько крошечно, что не имеет значения. Беспокойство по поводу дополнительной обработки является преждевременной оптимизацией и будет ничем по сравнению с показателями скорости, созданными для других разработчиков, чтобы «обнаружить», что вы преднамеренно использовали пустые строки.
Томас
3
Нет нулевых значений . Это страусиный подход. «Мы сунем голову в песок и объявим, что отсутствующие ценности не существуют». Это обычно приводит к решению Magic Value Solution, в котором вам нужно придумать магическое значение для каждого типа данных, чтобы представить отсутствие значения.
Томас
1

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

В программе мне не нравится нуль / ничего. Есть несколько исключений, но они только это. И эти исключения на самом деле просто плохие реализации.

Так что, если пользователь не вставил электронное письмо, должно быть что-то, что определяет, является ли это действительным или нет. Если пустое письмо в порядке, то оно отображает пустую строку. Если пользователь не вставил электронное письмо, и это нарушает правило, объект должен указать это.

Идея нулевого значения имеет смысл старой школы, и современные программисты должны ее обойти.

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

ElGringoGrande
источник
почему поле электронной почты не может содержать пустые значения и иметь строку нулевой длины - проще говоря: потому что любой разработчик, который знает что-либо о базах данных, никогда не ожидал бы, что пустые строки имеют магическое значение. Вы пытаетесь создать свою магическую ценность для представления того, что в принципе уже существует в каждой базе данных: концепция для представления отсутствия значения. Зачем изобретать велосипед? Кроме того, идея NULLS далека, далека от старой школы. Нули являются ключом к пониманию реляционной базы данных.
Томас
ЛОЛ. Как я уже говорил с точки зрения программистов, нулевые значения - это почти всегда боль в заднице и почти никогда не нужны для БИЗНЕС-ЛОГИКИ. Лично мне, как разработчику, не очень важен реляционный дизайн. Если бы я сделал, я был бы чувак БД. Если я получаю нулевое значение из БД, я почти всегда преобразую его в нечто рациональное, например, в пустую строку, и пусть мой великолепный ООП-дизайн делает свое волшебство. Фреймворк заботится о тех глупых нулевых силах, которые БДД навязывают миру. Я знаю, что парни из DB должны иметь дело с этим, и я чувствую к тебе. Но как программист я не обязан. У меня есть лучшие решения.
ElGringoGrande
Вам никогда не придется иметь дело с нулями. Итак, вы описываете страусовое решение в сочетании с магическим решением. «Я проигнорирую тот факт, что отсутствуют значения, и я преобразую все нулевые целые числа в -1». Пока не наступит день, когда -1 будет реальной стоимостью. Следует отметить, что одной из причин, по которой MS добавила универсальные элементы в .NET, было устранение значительного несоответствия импедансов между кодами баз данных и приложений, и это в основном сводилось к выражению нулей в коде среднего уровня. Эти «глупые нули» существуют и в бизнес-логике.
Томас
Тот факт, что какое-то целое число отсутствует в БД (или имеет значение null), не означает, что я должен представлять его с -1 или evan обнуляемым (int). Если вы думаете, что это единственный способ справиться с нулями, значит, вы не очень хорошо понимаете программирование. Помните, что нуль - это не то же самое, что ничто. Как вы сказали, null представляет заполнитель для отсутствующих значений в некоторой структуре данных. Это что-то значит. Бизнес-логика редко (что не то же самое, что никогда) нуждается в этом понятии, потому что она касается поведения, а не данных. И когда он имеет значение null, редко лучший способ представить это.
ElGringoGrande
Даже бизнес-логика должна учитывать (то есть представлять) отсутствующие ценности, и это верно в моем опыте, почти в каждой системе, которую я видел или строил за последние 20 лет. База данных моделирует бизнес-факты, которые нужно собирать и хранить. Если бизнес-логика хочет иметь возможность взаимодействовать с базой данных, она должна знать, как обращаться с нулями. Будь то пользовательская структура, магическое значение или универсальный не имеет значения. Бизнес-логика нуждается в способности обрабатывать получение отсутствующего значения из базы данных и возможность пометить значение как отсутствующее в базе данных.
Томас
-1

Я не думаю, что это имеет большое значение, но мне больше нравится, когда там NULL.

Когда я просматриваю данные, отображаемые в таблице (как в SQL Server Management Studio), я могу лучше различить отсутствующее значение, если оно говорит о NULL, а фон имеет другой цвет.

Если я вижу пустое пространство, мне всегда интересно, действительно ли оно пустое, или есть какие-то пробелы или какие-то невидимые символы. С NULL он гарантированно пуст с первого взгляда.

введите описание изображения здесь

Я обычно не различаю значения в приложении, потому что это неожиданно и странно, что NULL и пустая строка означают что-то другое. И большую часть времени я придерживаюсь оборонительного подхода и просто имею дело с обоими государствами. Но для меня, как человека, NULL легче обрабатывать при просмотре данных.

Том Пажурек
источник
кажется, это не дает ничего существенного по сравнению с замечаниями, сделанными и объясненными в предыдущих 12 ответах
комнат
@gnat: Я не согласен, никто в ответах не упомянул аспект просмотра данных человеком. Существует только одно значение NULL, но может быть множество значений, которые выглядят как пустые строки (не только пробелы, но и множество странных символов юникода). Я не вижу другого ответа, затрагивающего этот аспект проблемы.
Том Пажурек
насколько я могу судить, это было довольно хорошо изложено во втором топ-ответе, который был опубликован 5 лет назад: «Это очевидно для любого программиста, просматривающего базу данных ...» и т. д.
gnat
@gnat: Я понимаю вашу точку зрения, хотя я думаю, что автор не имеет в виду то же самое. Я полагаю, что он больше о том, что NULL подразумевает необязательные поля, но пустая строка может быть использована и для обязательных полей, поэтому NULL более логичен для пропущенного значения. Я с ним согласен. Но мой ответ указывает на тот факт, что пустая строка не так однозначна, как значение NULL, потому что многие вещи на первый взгляд могут выглядеть как пустые строки, хотя на самом деле не являются пустыми строками.
Том Пажурек