Postgres исключает NULL в WHERE id!= Int query

Вчера я столкнулся с непонятной проблемой в Postgres, пытаясь отфильтровать идентификаторы пользователей из таблицы статистики. Когда мы это сделали, например, user_id != 24, postgres исключили строки, в которых user_id есть NULL.

Я создал следующий тестовый код, который показывает те же результаты.

CREATE TEMPORARY TABLE test1 (
    id int DEFAULT NULL
);

INSERT INTO test1 (id) VALUES (1), (2), (3), (4), (5), (2), (4), (6), 
    (4), (7), (5), (9), (5), (3), (6), (4), (3), (7), 
    (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL);     

SELECT COUNT(*) FROM test1;

SELECT id, COUNT(*) as count
FROM test1
GROUP BY id;

SELECT id, COUNT(*) as count
FROM test1
WHERE id != 1
GROUP BY id;

SELECT id, COUNT(*) as count
FROM test1
WHERE (id != 1 OR id IS NULL)
GROUP BY id;

Первый запрос просто подсчитывает все строки. Второй подсчитывает количество каждого значения, включая нули. Третий исключает значение 1, а также все нули. Четвертый - это работа, чтобы исключить значение 1 и по-прежнему включать нули.

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

Работает ли единственный способ сделать это? Это ожидаемое поведение Postgres?

Ответ 1

Ваша "работа вокруг" - это обычный способ сделать это. Все ведет себя как ожидалось.

Причина проста: нули не равны и не равны ни для чего. Это имеет смысл, если вы считаете, что значение null означает "неизвестный", а истина сравнения с неизвестным значением также неизвестна.

Следствие таково:

  • null = null неверно
  • null = some_value неверно
  • null != some_value неверно

Существуют два специальных сравнения IS NULL и IS NOT NULL, предназначенные для тестирования, если столбец или нет, null. Никакие другие сравнения с нулем не могут быть правдой.

Ответ 2

Предикат IS DISTINCT FROM существует для этой цели. Это описано как:

не равно, рассматривая ноль как обычное значение

Так что просто делать id IS DISTINCT FROM 1 должно работать.

Ссылка: https://www.postgresql.org/docs/11/functions-comparison.html