Joins I — semantics
Concept  ·  SQL & Querying

NULL = NULL is UNKNOWN, so rows with a NULL join key quietly vanish from an INNER join.

NULL = anything is UNKNOWN, so a NULL key never satisfies the ON condition — the row simply does not participate. Nothing errors; the count is just smaller than the floor. The syntax (LEFT JOIN, COALESCE buckets) is the easy half; the real question is what the business wants done with the unmatched — an 'Unassigned' bucket, a separate count, or genuine exclusion — chosen, and written down.

See it break
carts
cartzone_id
c110
c2NULL
c320
c4NULL
zones
zone_idzone
10North
20South
The trap
SELECT
  c.cart,
  z.zoneFROM
  carts c
  JOIN zones z ON z.zone_id = c.zone_id
ORDER BY
  c.cart;
The fix
SELECT
  c.cart,
  COALESCE(z.zone, 'Unassigned') AS zone
FROM
  carts c
  LEFT JOIN zones z ON z.zone_id = c.zone_id
ORDER BY
  c.cart;
The trap
c1North
c3South
The fix
c1North
c2Unassigned
c3South
c4Unassigned

Two carts with a NULL zone quietly dropped from the compliance count — a NULL join key is never equal to anything, so the INNER join skips those rows.

The rule

LEFT JOIN with an explicit COALESCE bucket, a companion unmatched-count query, or a deliberate INNER JOIN with a comment saying so.

Shows up elsewhere
NULL = NULL is not TRUEThe LEFT JOIN that turned INNER
Try one →Prove it in practice →