Ответ
Пустая строка ('') и NULL — это принципиально разные концепции в реляционных базах данных.
Пустая строка ('')
- Что это: Значение строкового типа (
VARCHAR,TEXT), которое представляет собой строку нулевой длины. Это валидное, известное значение. - Аналогия в мире объектов:
string.Emptyв C# или""в Java. - Хранение: Занимает место в строке таблицы (для хранения информации о длине строки, которая равна 0).
NULL
- Что это: Специальный маркер, означающий отсутствие какого-либо значения, «значение не известно», «не применимо» или «не указано». Это не строка, не число и не ноль.
- Аналогия в мире объектов:
nullв C#/Java илиNoneв Python. - Хранение: Обычно требует отдельного бита в строке для указания, что поле
NULL. Само значение не хранится.
Практические различия и примеры SQL
-- Создадим тестовую таблицу
CREATE TABLE Users (
Id INT PRIMARY KEY,
Name VARCHAR(100),
Nickname VARCHAR(100)
);
-- Вставим разные значения
INSERT INTO Users (Id, Name, Nickname) VALUES
(1, 'Alice', ''), -- Nickname — пустая строка (пользователь сознательно оставил поле пустым)
(2, 'Bob', NULL), -- Nickname — NULL (пользователь не заполнял поле вообще)
(3, 'Charlie', 'Chuck'); -- Nickname — обычное значение
-- КРИТИЧНО ВАЖНЫЕ РАЗЛИЧИЯ В ЗАПРОСАХ:
-- 1. Сравнение: для NULL используется специальный оператор IS
SELECT * FROM Users WHERE Nickname = ''; -- Найдет только Alice (Id=1)
SELECT * FROM Users WHERE Nickname IS NULL; -- Найдет только Bob (Id=2)
SELECT * FROM Users WHERE Nickname = NULL; -- Этот запрос ВСЕГДА вернет пустой результат! (синтаксически верно, но логически не работает)
-- 2. Агрегатные функции игнорируют NULL
SELECT COUNT(Nickname) FROM Users; -- Вернет 2 (Alice и Charlie). NULL (Bob) проигнорирован.
SELECT AVG(LENGTH(Nickname)) FROM Users; -- Учтет только не-NULL значения (Alice=0, Charlie=5).
-- 3. Конкатенация с NULL дает NULL
SELECT Name || ' (' || Nickname || ')' FROM Users;
-- Результат: 'Alice ()', NULL (для Bob), 'Charlie (Chuck)'
-- Для Bob вся строка стала NULL, потому что один из операндов — NULL.
-- Чтобы избежать этого, используют COALESCE: Name || ' (' || COALESCE(Nickname, 'N/A') || ')'
Связь с кодом приложения (C# пример)
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Правильное чтение из БД с учетом NULL
string name = reader["Name"] as string; // Если в БД NULL, то в коде будет null
object nicknameRaw = reader["Nickname"];
// Проверка на DBNull (специальный тип для представления NULL из БД в .NET)
string nickname;
if (nicknameRaw == DBNull.Value)
{
nickname = null; // Значение было NULL в БД
}
else
{
nickname = (string)nicknameRaw; // Может быть "" или обычная строка
}
// Альтернатива — использовать reader.IsDBNull(columnIndex)
// Или современные ORM (Entity Framework) делают это преобразование автоматически.
}
}
Итог: Когда что использовать?
- Используйте
NULL, когда значение неизвестно, не применимо или не предоставлено (например, дата увольнения для действующего сотрудника). - Используйте пустую строку, когда значение известно и сознательно оставлено пустым (например, поле "Отчество", если его нет).
Важное замечание: В некоторых СУБД (например, Oracle) пустая строка ('') автоматически преобразуется в NULL. Это частый источник ошибок при миграции между базами данных. Всегда проверяйте поведение вашей целевой СУБД.
Ответ 18+ 🔞
А, ну вот, опять про эту вечную путаницу! Слушай, тут есть один нюанс, который половина разработчиков на старте не понимает, а потом голову ломают, почему запросы не работают. Речь про пустую строку и NULL. Это, блядь, как сравнивать ноль с отсутствием числа вообще — две большие разницы, ёпта!
Пустая строка ('') — это типа как ты пришёл на работу, а у тебя на столе лежит чистый лист бумаги. Значение есть, оно известно — просто там нихуя не написано. В базе это валидная строка, просто длины ноль.
NULL — это когда ты вообще не подходил к столу и понятия не имеешь, есть там что-то или нет. Значение отсутствует, не определено, не применимо. Это не строка, не число, это просто специальная метка «хуй его знает».
Вот смотри, на живом SQL:
-- Допустим, есть табличка с пользователями
CREATE TABLE Users (
Id INT PRIMARY KEY,
Name VARCHAR(100),
Nickname VARCHAR(100)
);
-- Кидаем туда данные
INSERT INTO Users (Id, Name, Nickname) VALUES
(1, 'Алиса', ''), -- Псевдоним — пустая строка (типа «оставила поле пустым»)
(2, 'Боб', NULL), -- Псевдоним — NULL (вообще не заполнял, похуй)
(3, 'Чарли', 'Чак'); -- Ну тут всё понятно
-- А теперь самое интересное, где все и обламываются!
SELECT * FROM Users WHERE Nickname = ''; -- Найдёт только Алису (Id=1)
SELECT * FROM Users WHERE Nickname IS NULL; -- Найдёт только Боба (Id=2)
SELECT * FROM Users WHERE Nickname = NULL; -- А вот эта хуйня ВСЕГДА вернёт пустой результат! Запомни это как «Отче наш»!
Видишь разницу? С NULL нельзя сравнивать через =, для него есть специальный оператор IS. Иначе запрос просто сдохнет молча, и будешь потом ебаться, искать, почему данные не находятся.
Ещё прикол: агрегатные функции, типа COUNT() или AVG(), NULL просто игнорируют, как будто его нет. А пустую строку — учитывают.
SELECT COUNT(Nickname) FROM Users; -- Вернёт 2 (Алису и Чарли). Боба проигнорировали, потому что у него NULL.
Ну и в коде, когда выгребаешь это всё, тоже надо голову включать. Вот на C#:
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Так делать — пиздец
// string nickname = reader["Nickname"].ToString(); // Упадешь, если там NULL
// Надо вот так, с проверкой на этот самый DBNull
object rawValue = reader["Nickname"];
string nickname;
if (rawValue == DBNull.Value)
{
nickname = null; // Было NULL в базе
}
else
{
nickname = (string)rawValue; // А тут уже либо "", либо нормальная строка
}
// Современные ORM типа Entity Framework эту проверку делают за тебя, но знать-то надо!
}
}
Итог, чтобы не быть мудаком:
NULLюзаешь, когда значение неизвестно или не применимо. Например, «Дата увольнения» для того, кто ещё работает.- Пустую строку — когда значение известно и сознательно оставлено пустым. Например, поле «Отчество», если его у человека нет.
И да, блядь, важный лайфхак: в Oracle пустая строка ('') автоматически конвертится в NULL! Вот так вот, ебаный насос. Так что если пишешь кроссплатформенную хуйню, имей это в виду, а то будут сюрпризы.