← Назад к вопросам

Совпадает ли значение NULL со значением нуля?

2.0 Middle🔥 141 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Совпадает ли NULL со значением нуля? Глубокий анализ

Краткий ответ

НЕТ. NULL и 0 — это совершенно разные концепции.

Различия

NULL:
- Отсутствие значения
- Unknown, undefined
- Не равно ничему, даже себе (NULL != NULL)
- Занимает место в БД
- Нужна специальная проверка: IS NULL

0:
- Ноль
- Число, которое равно нулю
- Может быть результатом вычисления
- Обычное значение
- Сравнивается нормально: value = 0

SQL примеры

Пример 1: Сравнение

-- Таблица с данными
CREATE TABLE users (
    id INT,
    name VARCHAR(100),
    age INT,
    salary DECIMAL(10, 2)
);

INSERT INTO users VALUES
(1, 'John', 30, 50000),
(2, 'Jane', NULL, 60000),    -- age неизвестен
(3, 'Bob', 25, 0),           -- зарплата 0
(4, 'Alice', NULL, NULL);    -- age и salary неизвестны

-- Query: найти всех с age = 0
SELECT * FROM users WHERE age = 0;
Result: 0 rows (никого не найдёт)
         (потому что age неизвестен, не 0)

-- Query: найти всех с age IS NULL
SELECT * FROM users WHERE age IS NULL;
Result: 2 rows (Jane и Alice)

-- Query: найти всех с salary = 0
SELECT * FROM users WHERE salary = 0;
Result: 1 row (Bob имеет зарплату 0)

-- Query: найти всех с salary IS NULL
SELECT * FROM users WHERE salary IS NULL;
Result: 1 row (Alice)

Пример 2: Арифметика с NULL

SELECT 
  age,
  salary,
  salary / 12 AS monthly_salary
FROM users;

Result:
age | salary | monthly_salary
----|--------|---------------
30  | 50000  | 4166.67
NULL| 60000  | 5000.00
25  | 0      | 0.00
NULL| NULL   | NULL

Замечание:
- Row 2: age=NULL, но это не влияет на расчёт salary
- Row 4: salary=NULL, поэтому результат NULL
  (NULL + любое число = NULL)

Пример 3: COALESCE (заменить NULL)

SELECT 
  name,
  age,
  COALESCE(age, 0) AS age_or_zero
FROM users;

Result:
name  | age  | age_or_zero
------|------|------------
John  | 30   | 30
Jane  | NULL | 0
Bob   | 25   | 25
Alice | NULL | 0

Объяснение:
COALESCE(age, 0) значит:
  IF age IS NULL THEN 0 ELSE age

Различия в различных контекстах

JavaScript / TypeScript

// В JS нет NULL и UNDEFINED, есть оба!
let a = null;      // explicitly null
let b = undefined; // no value
let c = 0;         // number zero

a == c;        // false (null != 0)
a == undefined // true (quirk of JS)
NaN == 0;      // false

// Проверка
if (value === null) { }      // only null
if (value === 0) { }         // only zero
if (value == null) { }       // both null and undefined
if (!value) { }              // null, undefined, 0, '', false, NaN

Python

a = None      # Python's NULL
b = 0         # zero

a == b        # False
a is None     # True

# Проверка
if value is None:
    pass
if value == 0:
    pass

PostgreSQL

SELECT NULL = 0;           -- NULL (not false!)
SELECT NULL = NULL;        -- NULL (never true)
SELECT NULL IS NULL;       -- true
SELECT 0 IS NULL;          -- false

-- Специальная функция для проверки
SELECT COALESCE(NULL, 'default'); -- 'default'
SELECT COALESCE(0, 'default');    -- 0

Case 1: Bug которую я выловил

Ситуация: Аналитика данных показывала неправильные результаты.

Код разработчика:

# Неправильно!
def calculate_average_age(users):
    sum_age = 0
    count = 0
    
    for user in users:
        if user.age != 0:  # ← ОШИБКА! NULL != 0 но NULL != 0 тоже истинно!
            sum_age += user.age  # NULL + число = ошибка
            count += 1
    
    return sum_age / count if count > 0 else 0

# Результат:
users = [
  {age: 30},
  {age: None},     # age неизвестен
  {age: 25}
]

average = calculate_average_age(users)
# Ошибка: TypeError (can't add NoneType to int)

Правильный код:

def calculate_average_age(users):
    ages = [u.age for u in users if u.age is not None]  # Исключить NULL
    return sum(ages) / len(ages) if ages else 0

# Или более компактно
ages = [u.age for u in users if u.age]
# ⚠️ Внимание! Это исключит и NULL, и 0!
# Лучше явно: if u.age is not None

Lesson: NULL и 0 — это разные вещи. Проверяй явно.

Case 2: Неправильная фильтрация

Ситуация: Отчёт показывает "завершённые заказы", но результаты неправильные.

SQL:

-- Неправильно!
SELECT * FROM orders 
WHERE completed_at != NULL;

Result: 0 rows

Почему? Потому что:
  NULL != NULLNULL (not true)
  NULL != любое_значение → NULL (not true)
  Условие WHERE требует true, NULLtrue
  Результат: 0 rows

Правильно:

SELECT * FROM orders 
WHERE completed_at IS NOT NULL;

Result: все заказы которые завершены

Lesson: ВСЕГДА используй IS NULL и IS NOT NULL для NULL проверок.

Case 3: GROUP BY и NULL

Ситуация: Группировка результатов по статусу платежа.

CREATE TABLE payments (
    id INT,
    amount DECIMAL(10, 2),
    status VARCHAR(20)  -- 'completed', 'pending', NULL
);

INSERT INTO payments VALUES
(1, 100, 'completed'),
(2, 200, 'pending'),
(3, 150, NULL),        -- status unknown
(4, 300, 'completed'),
(5, 50, NULL);         -- status unknown

-- Query: Group by status
SELECT status, COUNT(*) as count, SUM(amount) as total
FROM payments
GROUP BY status;

Result:
status    | count | total
----------|-------|-------
NULL      | 2     | 200
completed | 2     | 400
pending   | 1     | 200

Объяснение:
- NULL payments группируются вместе
- Хотя NULL != NULL в WHERE
- В GROUP BY, NULL = NULL (создаёт группу)
- Это потому что SQL рассматривает NULL как distinct value для группировки

Практический пример:

Для аналитики, можно заменить NULL на "Unknown":

SELECT 
  COALESCE(status, 'Unknown') as status,
  COUNT(*) as count,
  SUM(amount) as total
FROM payments
GROUP BY COALESCE(status, 'Unknown');

Result:
status    | count | total
----------|-------|-------
Unknown   | 2     | 200
completed | 2     | 400
pending   | 1     | 200

(Теперь видно, что 2 платежа с неизвестным статусом)

Case 4: Индексы и NULL

Ситуация: Поиск по индексированному полю.

-- Таблица с индексом
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,  -- Уникальный индекс
    phone VARCHAR(20)           -- Обычное поле
);

INSERT INTO users VALUES
(1, 'john@example.com', '123-456'),
(2, 'jane@example.com', NULL),
(3, 'bob@example.com', '789-012'),
(4, NULL, NULL);  -- ← Можно ли вставить?

-- PostgreSQL: ДА, можно вставить NULL в UNIQUE
-- MySQL: ДА, можно вставить несколько NULL
-- SQL Server: ДА (но зависит от версии)
-- Oracle: ДА

-- Поиск по NULL
SELECT * FROM users WHERE phone IS NULL;
Result: 2 rows (jane и anonymous user)

SELECT * FROM users WHERE phone = NULL;
Result: 0 rows (NULL != NULL, всегда)

Best Practices

1. Всегда проверяй NULL явно

-- ❌ Неправильно
WHERE field != NULL
WHERE field = NULL

-- ✓ Правильно
WHERE field IS NULL
WHERE field IS NOT NULL

2. Используй COALESCE для default values

SELECT 
  name,
  COALESCE(age, 'Unknown') as age_display,
  COALESCE(salary, 0) as salary_display
FROM users;

3. В коде, проверяй NULL перед использованием

# ❌
value = dict.get('key')  # Может быть None
result = value + 10      # Ошибка если None

# ✓
value = dict.get('key')
if value is not None:
    result = value + 10
else:
    result = 0

# ✓ Или
value = dict.get('key', 0)  # Default to 0
result = value + 10

4. Различай NULL в БД и в коде

-- БД может иметь:
value = NULL    -- Отсутствие значения
value = 0       -- Ноль
value = ''      -- Пустая строка

-- В коде нужно обработать разные случаи:
if value is None:      # NULL из БД
    ...
elif value == 0:       # Ноль
    ...
elif value == '':      # Пустая строка
    ...

5. Документируй, какие поля могут быть NULL

CREATE TABLE users (
    id INT NOT NULL,           -- Обязательное
    name VARCHAR(100) NOT NULL, -- Обязательное
    email VARCHAR(100),         -- Может быть NULL
    age INT,                   -- Может быть NULL
    phone VARCHAR(20),         -- Может быть NULL
    company_id INT             -- FK, может быть NULL
);

-- Или в документации:
"email: Optional, can be NULL if not provided"
"age: Optional, NULL means age unknown"

Когда используется NULL

Уместно:

  • Поле где value неизвестен (age, phone)
  • Optional field'ы
  • Внешние ключи для опциональных relations

Неуместно:

  • Использовать 0 или -1 вместо NULL (плохо)
  • Использовать пустую строку '' вместо NULL для текста
  • Использовать NULL для флага (используй boolean)

Вывод

NULL ≠ 0

NULL:        Отсутствие информации
0:           Число ноль
'':          Пустая строка
false:       Логический false
undefined:   Неинициализированное значение

Каждое — это разные концепции!

Проверка:
value is null    ✓
value = 0        ✓
value = ''       ✓

value = null     ✗ (почти всегда неправильно)
value != null    ✗ (почти всегда неправильно)

System Analyst должен понимать эти различия, чтобы:

  1. Правильно спроектировать БД schema
  2. Документировать какие поля могут быть NULL
  3. Обсудить с разработчиками как обрабатывать NULL
  4. Выловить bugs связанные с NULL обработкой

Это кажется простым, но это один из самых распространённых источников bugs в production.

Совпадает ли значение NULL со значением нуля? | PrepBro