NULL & three-valued logic
Concept  ·  SQL & Querying

IS DISTINCT FROM treats NULL as a comparable value — two NULLs are not distinct — the null-safe = and <> for keys, change detection, and dedup.

Ordinary comparison answers 'are these values equal?' and refuses to answer about unknowns; DISTINCT-comparison answers 'are these cells the same?' — a bookkeeping question where NULL-vs-NULL is legitimately 'same' and NULL-vs-1 legitimately 'different'. That's the semantics set operations already use internally — this operator is that semantics, in a WHERE clause.

See it break
cat
idoldnew
1NULLheirloom
2aa
3bNULL
The trap
SELECT
  id
FROM
  cat
WHERE
  old <> new
ORDER BY
  id;
The fix
SELECT
  id
FROM
  cat
WHERE
  old IS DISTINCT FROM new
ORDER BY
  id;

The change scan missed the row where old was NULL and new was 'heirloom' — <> returns UNKNOWN when either side is NULL, so it drops the NULL→value and value→NULL transitions that IS DISTINCT FROM catches.

The rule

DISTINCT-comparison wherever nullable columns are compared for identity.

Standard in Postgres/DuckDB; Snowflake EQUAL_NULL(); elsewhere (a = b OR (a IS NULL AND b IS NULL)) is the portable expansion.

Shows up elsewhere
Set ops treat NULLs as equalAnti-join three ways
Try one →Prove it in practice →