Aggregation & GROUP BY
Concept  ·  SQL & Querying

GROUP BY collects all NULL keys into a single group — not skipped.

Grouping treats NULL like set operations do (same 'same absence' semantics), not like = does — so untagged rows don't vanish (a mercy) but they masquerade as a category. The failure is downstream and human: the NULL row renders blank in the BI tool, sorts to an edge, or gets COALESCEd to 'Other' where it merges with a real 'Other'. Treat a growing NULL group as the data-quality alarm it is.

See it break
coats
tag
red
NULL
NULL
The trap
SELECT
  tag, COUNT(*) AS n
FROM
  coats
GROUP BY
  tag
ORDER BY
  tag NULLS LAST;
The fix
SELECT
  COALESCE(tag, '<untagged>') AS tag,
  COUNT(*) AS n
FROM
  coats
GROUP BY
  tag
ORDER BY
  tag NULLS LAST;
INPUTYour queryThe fix
red12
NULL21

The two untagged coats didn't vanish — GROUP BY collected them into one NULL group of 2, which renders blank and masquerades as a category; COALESCE labels it with a value that can't collide.

The rule

Explicit non-colliding label; a stated include/exclude decision; the NULL-group count as a monitored metric.

Shows up elsewhere
Set ops treat NULLs as equalNULL sort position differs by engine
Try one →Prove it in practice →