Перейти к основному содержимому

Фильтрация и трёхзначная логика

Разработчику Аналитику Тестировщику

Логические операторы

ОператорСмысл
ANDИстина, только если оба операнда истинны
ORИстина, если хотя бы один операнд истинен
NOTИнверсия

Приоритет: NOTANDOR.

Без скобок выражение a OR b AND c читается как a OR (b AND c). Для (a OR b) AND c скобки обязательны.

SELECT last_name, department, salary
FROM employees
WHERE (department = 'Sales' OR department = 'Marketing')
AND salary >= 80000;

Сравнение с NULL

В SQL три значения предиката: TRUE, FALSE, UNKNOWN (когда участвует NULL).

ВыражениеРезультат
NULL = NULLUNKNOWN
NULL <> NULLUNKNOWN
NULL > 5UNKNOWN
5 = NULLUNKNOWN

Строка с UNKNOWN в WHERE не попадает в результат (как при FALSE).

Правильная проверка:

SELECT name FROM employees WHERE manager_id IS NULL;
SELECT name FROM employees WHERE manager_id IS NOT NULL;

Ошибка — сравнение с NULL через =:

-- неверно: всегда пустой результат
SELECT name FROM employees WHERE manager_id = NULL;

-- верно
SELECT name FROM employees WHERE manager_id IS NULL;

UNKNOWN в AND и OR

ВыражениеРезультат
TRUE AND UNKNOWNUNKNOWN
FALSE AND UNKNOWNFALSE
TRUE OR UNKNOWNTRUE
FALSE OR UNKNOWNUNKNOWN
NOT UNKNOWNUNKNOWN

NOT IN и NULL

value NOT IN (1, 2, NULL) даёт UNKNOWN для любого value, потому что сравнение с NULL не даёт TRUE. Итог — пустая выборка.

Используйте NOT EXISTS или исключите NULL из подзапроса (см. Подзапросы, EXISTS и IN).


PostgreSQL: IS DISTINCT FROM

Обычное сравнение не различает «оба NULL» и «оба не NULL». Оператор IS DISTINCT FROM трактует два NULL как равные:

SELECT a, b
FROM t
WHERE a IS DISTINCT FROM b; -- строки, где значения различаются (включая NULL)

SELECT a, b
FROM t
WHERE a IS NOT DISTINCT FROM b; -- эквивалент «равно с учётом NULL»

Практические рекомендации

  • При смешении AND и OR всегда ставьте скобки, даже если приоритет «очевиден».
  • Для опциональных полей явно ветвите: (col = :val OR (:val IS NULL AND col IS NULL)) или COALESCE.
  • Избегайте NOT IN с подзапросами без гарантии NOT NULL в сравниваемом столбце.
  • Для поиска по шаблону: LIKE 'префикс%' может использовать индекс; LIKE '%суффикс' — обычно нет (без pg_trgm).

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

CREATE TABLE employees (
emp_id SERIAL PRIMARY KEY,
last_name TEXT NOT NULL,
department TEXT,
salary NUMERIC(10, 2)
);

SELECT last_name, department, salary
FROM employees
WHERE department IS NULL
OR salary > 100000;

Контрольные вопросы

  1. Почему WHERE bonus = NULL не находит строки с пустым бонусом?
  2. Чем FALSE AND UNKNOWN отличается от TRUE AND UNKNOWN?
  3. Когда NOT IN безопаснее заменить на NOT EXISTS?
  4. Зачем нужен IS DISTINCT FROM?

См. также


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).