Back to Blog

Why Your AI's 'Missing Email' Count Ignores Blank Emails

Asked how many customers have no email and got only the NULL rows. Forms often save '' instead of NULL. IS NULL does not match empty strings — and the two are not interchangeable across Postgres, MySQL, and Oracle-style installs.

You ask "how many customers have no email?" The AI writes WHERE email IS NULL and returns 140. You know hundreds of people signed up without typing one. The form stored '', not NULL. Those rows are not missing to SQL — they have a value. It's just empty.

'' is a value

WHERE email IS NULL          -- 140 rows
WHERE email = ''             -- 610 rows
WHERE email IS NULL OR email = ''   -- 750 rows

Three different answers to what sounded like one question. No error. The first one is what models reach for because "no email" maps cleanly onto NULL in textbooks — and because Oracle treats '' as NULL, a habit that does not apply to Postgres, MySQL, or SQL Server.

This sits next to IS NULL dropping rows from != filters and COUNT(column) skipping NULLs. Those are about NULL's three-valued logic. This one is about the other missing: a present, empty string the UI still shows as blank.

How to catch it

Ask for the split, not one number:

How many customers have email IS NULL?
How many have email = ''?
How many have TRIM(email) = ''?
Show all three and the SQL.

If the second or third is non-zero, a NULL-only "missing" count is incomplete. Same check for name, phone, notes, plan — any field a form can submit empty.

One-liner that treats both as missing:

WHERE NULLIF(TRIM(email), '') IS NULL

NULLIF(x, '') turns '' into NULL; TRIM folds whitespace-only into the same bucket.

The prompt that heads this off

When I ask for missing / blank / no X, don't use IS NULL alone.
Check describe_table, then count NULL, '', and TRIM(column) = ''
separately unless I say the column is never empty-string.
Prefer NULLIF(TRIM(column), '') IS NULL for "no usable value."

The short version

Blank in the admin UI is not one SQL thing. NULL and '' are different rows. If the "no email" count looks low, you probably only counted the first.


Read-only MCP gateway: mcpserver.design.

Related reading: