WHERE col = ''查不到NULL行,因为NULL = ''返回UNKNOWN,而WHERE只接受TRUE;它仅匹配显式插入空字符串的行,NULL需用col IS NULL单独判断。

因为NULL不是值,而''是值——SQL标准规定所有涉及NULL的等值比较都返回UNKNOWN,而WHERE只接受TRUE。
WHERE col = '' 为什么查不到 NULL 行
执行 WHERE col = '' 时,数据库对每一行计算该表达式:若 col 是 NULL,则 NULL = '' 的结果是 UNKNOWN(既不是 TRUE 也不是 FALSE);而 WHERE 子句只保留计算结果为 TRUE 的行,UNKNOWN 被直接排除。这不是 MySQL 特有,是所有遵循 SQL 标准的数据库(PostgreSQL、SQL Server、Oracle)的统一行为。
-
col = ''→ 只匹配显式插入''的行(如INSERT INTO t(x) VALUES ('')) -
col IS NULL→ 只匹配未赋值、或显式写NULL的行(如INSERT INTO t(x) VALUES (NULL)或字段无默认值且 INSERT 时省略该列) -
col = NULL永远不生效——语法合法但逻辑恒假,别写
ORM 和低代码工具常在这里翻车
很多框架默认把前端空表单提交当作“空字符串”,生成 WHERE name = '',完全不考虑 IS NULL 分支。Django 的 .filter(name='') 、SQLAlchemy 的 filter(Model.name == '') 都是这样。你看到页面上显示“空白”,但数据库里混着 '' 和 NULL,查出来就漏一半。
- 检查实际生成的 SQL:开日志或用
str(query.statement)(SQLAlchemy)、query.sql(Django)看清楚 - 不要依赖“界面上看起来一样”做判断;执行
SELECT id, col, LENGTH(col), col IS NULL FROM t WHERE col IN ('', NULL) OR col IS NULL LIMIT 5真实验证数据分布 - 如果业务语义就是“没内容”,必须手动补全:比如 Django 改成
.extra(where=["col = '' OR col IS NULL"])或用Q对象组合
COALESCE(col, '') = '' 看似简洁,但有陷阱
这个写法在 MySQL/PostgreSQL/SQL Server 中确实能同时命中 '' 和 NULL,但它掩盖了语义差异,还带来性能隐患:
- 它把
NULL转成''再比,但如果你后续要做ORDER BY或GROUP BY,''和原生NULL排序位置不同(MySQL 中NULL默认排最前,''按字典序排在' '后、'a'前) -
COALESCE(TRIM(col), '') = ''这类带函数的条件无法走普通索引,高频查询会变慢 - Oracle 是例外:
''在 Oracle 里被当NULL处理,= ''永远不返回任何行,COALESCE(col, '')实际等于col,写了也白写
真正麻烦的从来不是写错一个条件,而是建表那一刻没想清楚:这个字段的“空白”到底代表“用户填了空”还是“根本没填”。一旦混合存入,所有查询、导出、连表、统计都会悄悄偏移——而且这种偏差往往要等到报表对不上数时才被发现。

















