WHERE col = ''查不到NULL记录,因为NULL = ''返回UNKNOWN,而WHERE只保留TRUE结果;需用col = '' OR col IS NULL或COALESCE(col, '') = ''同时覆盖两者。

WHERE col = '' 为什么查不到 NULL 记录
因为 NULL = '' 的结果是 UNKNOWN,而 WHERE 子句只保留判断结果为 TRUE 的行。这不是某个数据库的 bug,而是 SQL 标准强制要求的三值逻辑行为。
常见错误现象:界面上字段显示“空白”,你写 WHERE email = '' 却漏掉大量数据——那些其实是 NULL,不是空字符串。
- ORM(如 Django 的
filter(email=''))默认只生成= '',不会自动补IS NULL - 验证方法:执行
SELECT email, LENGTH(email), email IS NULL FROM users WHERE email IN ('', NULL) OR email IS NULL LIMIT 5,一眼看出哪些是真''、哪些是NULL - MySQL/PostgreSQL/SQL Server 行为一致;Oracle 是例外——它把
''当作NULL处理,= ''实际等价于IS NULL
SELECT COUNT(col) 和 COUNT(*) 对 NULL 与 '' 的处理差异
COUNT(*) 统计所有行,不管列值是什么;COUNT(col) 只统计 col IS NOT NULL 的行——也就是说,NULL 被跳过,但 '' 会被计入。
这直接影响业务统计:比如“有效邮箱数”若用 COUNT(email),会把 '' 算进去,但漏掉 NULL;而“填写了邮箱的用户数”本意应排除两者。
- 要真正统计“非空非缺失”的字符串,得写
COUNT(CASE WHEN email != '' AND email IS NOT NULL THEN 1 END) -
SUM()、AVG()、MAX()、MIN()全部跳过NULL,但对''的行为不一:PostgreSQL 直接报错(类型不匹配),MySQL 可能隐式转成0导致静默偏差 - 如果想让聚合统一忽略
''和NULL,先用NULLIF(email, '')把空串转成NULL,再套COUNT()或AVG()
ORDER BY 中 NULL 和 '' 的排序位置为什么总不一致
NULL 的排序位置由方言和显式子句控制:NULLS FIRST 或 NULLS LAST 是标准写法,但 MySQL 不支持,且默认把 NULL 排最前;PostgreSQL 默认排最后。而 '' 始终按字典序参与排序,ASCII 值为 0,所以永远比 ' '(空格)靠前、比 'a' 靠前。
这意味着:同一份 ORDER BY name 查询,在不同数据库里,NULL 行可能忽上忽下,但 '' 行位置稳定。如果你依赖前端分页顺序,这个差异会直接暴露为数据错乱。
- 跨库兼容写法:显式声明
ORDER BY name NULLS LAST(PostgreSQL/Oracle 支持),或用ORDER BY (name IS NULL), name模拟(通用) -
COALESCE(name, '')能把NULL转成''再排序,但注意:这会让NULL和''在结果中混在一起、无法区分 - 真实业务中,
NULL往往表示“未采集”,''可能表示“用户主动留空”,语义不同,强行合并排序可能掩盖问题
INSERT 时写 '' 和 NULL 到同一字段,后续查询怎么写才不漏数据
不能只靠 = '' 或只靠 IS NULL ——必须明确你要覆盖的语义。业务上“无内容”通常包含两种情况:从未填(NULL)和填了但为空('')。
最直白安全的写法是 WHERE col = '' OR col IS NULL;更紧凑的是 WHERE COALESCE(col, '') = '',它在 MySQL/PostgreSQL/SQL Server 都可用。
-
COALESCE(col, '') = ''的逻辑是:若col为NULL,取'';若col已是'',就直接比较——两者都命中 - 反过来,若你想排除所有“无效字符串”,用
NULLIF(col, '') IS NULL(即:把''转NULL后再判空) - Oracle 用户注意:插入
''会被自动转成NULL,所以表里实际只有NULL,不存在真正的'';查的时候只能用IS NULL,= ''无效

















