NULL обозначает отсутствие известного значения, поэтому стандартные операторы сравнения
= и <> не позволяют корректно определить равенство или различие, если один из операндов содержит NULL.Например:
NULL <> 'new value'
Результатом выражения будет NULL, а не TRUE или FALSE. Это связано с трёхзначной логикой SQL: результат сравнения с неизвестным значением также является неизвестным.
Поэтому проверки изменения данных с использованием обычных операторов сравнения требуют дополнительной обработки:
column <> new_value
OR (column IS NULL AND new_value IS NOT NULL)
OR (column IS NOT NULL AND new_value IS NULL)
Оператор
IS DISTINCT FROM решает эту задачу, выполняя сравнение с явным учетом NULL и всегда возвращая логическое значение. Пример обновления пользователя только при фактическом изменении email:UPDATE users
SET email = :new_email
WHERE id = :id
AND email IS DISTINCT FROM :new_email;
Если значения совпадают, строка обновлена не будет. Если одно значение содержит NULL, а другое — данные, оператор определит их как различные.
Оператор также корректно обрабатывает случай, когда оба значения равны NULL:
SELECT NULL IS DISTINCT FROM NULL;
Результат:
false
В логике
IS DISTINCT FROM два значения NULL считаются одинаковыми, так как оба представляют отсутствие значения. Без использования данного оператора аналогичная проверка требует дополнительных условий:email <> :new_email
OR (email IS NULL AND :new_email IS NOT NULL)
OR (email IS NOT NULL AND :new_email IS NULL)
IS DISTINCT FROM заменяет такую конструкцию одним выражением и делает сравнение nullable-полей более предсказуемым.При обновлении сущностей через API, синхронизации данных и импорте часто возникает ситуация, когда передаётся полный объект, хотя часть полей не изменилась. Обычный запрос:
UPDATE users
SET
email = :new_email,
name = :new_name
WHERE id = :id;
выполнит обновление независимо от фактического изменения значений.
В PostgreSQL это приводит к созданию новой версии строки в рамках MVCC, увеличению объёма WAL, дополнительным вызовам триггеров и генерации ненужных событий при использовании репликации или систем обработки изменений. Более точный вариант:
UPDATE users
SET
email = :new_email,
name = :new_name
WHERE id = :id
AND (
email IS DISTINCT FROM :new_email
OR name IS DISTINCT FROM :new_name
);
Такой подход позволяет выполнять обновление только при изменении данных. Он применяется в API, системах синхронизации, импортерах данных и интеграционных процессах.
🔥
IS DISTINCT FROM — оператор, который обеспечивает корректное сравнение значений с NULL и помогает избегать лишних операций записи в базе данных.➡️ SQL Ready | #практика