NULL与''在SQL中行为截然不同:WHERE col = NULL恒不成立,须用IS NULL;空字符串用= ''匹配;聚合函数对二者处理差异大,需用NULLIF或COALESCE统一处理。

NULL 与 '' 在 WHERE 条件中的行为完全不同
直接写 WHERE col = '' 能命中空字符串,但 WHERE col = NULL 永远不返回任何行——因为 SQL 中任何与 NULL 的等值比较(=、!=、)结果都是 UNKNOWN,而 WHERE 只接受 TRUE。
查 NULL 必须用 IS NULL,查非空字符串且排除 NULL 得写成:col != '' AND col IS NOT NULL。
-
col = '':只匹配存储值为零长度字符串的行 -
col IS NULL:只匹配该列未赋值或显式设为NULL的行 -
col = NULL或col != NULL:语法合法,但逻辑恒为假,无实际筛选效果 - 某些 ORM(如 Django)自动生成的查询可能混淆二者,需检查生成 SQL
聚合函数对 NULL 和 '' 的处理差异
COUNT(col) 忽略 NULL,但会计入 '';SUM()、AVG()、MAX()、MIN() 全部跳过 NULL,却把 '' 当作有效值参与计算——这在字符类型上通常报错(如 SUM('') 在 PostgreSQL 报 invalid input syntax for type numeric),但在 MySQL 的宽松模式下可能隐式转为 0,造成静默偏差。
-
COUNT(*)统计所有行,COUNT(col)只统计col IS NOT NULL的行 -
COALESCE(col, 'N/A')可统一兜底,但注意:若col是'',不会触发替换 - 用
NULLIF(col, '')可把空字符串转为NULL,再配合聚合更安全
ORDER BY 中 NULL 和 '' 的排序位置受方言控制
标准 SQL 规定 NULLS FIRST / NULLS LAST,但 MySQL 默认把 NULL 排最前,PostgreSQL 默认排最后;而 '' 始终按字典序参与排序,和普通字符串一样。这意味着 ORDER BY name 的结果在不同数据库里,NULL 行的位置可能上下翻转,但 '' 行总在 'a' 前、' ' 后(因 ASCII 值为 0)。
- MySQL 8.0+ 支持显式
NULLS LAST,但旧版只能靠ORDER BY IF(col IS NULL, 1, 0), col模拟 -
''和' '(空格)不是一回事:LENGTH(' ')是 1,LENGTH('')是 0 -
前端分页时若依赖排序稳定性,必须明确处理
NULL位置,否则同一页数据可能重复或丢失
INSERT 和 DEFAULT 对 NULL 与 '' 的隐式转换风险
定义列为 TEXT DEFAULT '' 时,显式插入 NULL 会存成 NULL(除非加 NOT NULL 约束);但若列定义为 TEXT DEFAULT NULL,又没指定值,才真正存 NULL。更大的陷阱是某些客户端或 ORM 在字段为空时自动发 '' 而非 NULL,导致业务上“未填写”被记为“填了空值”。
- 建表时优先用
NOT NULL DEFAULT ''明确语义,避免歧义 - MySQL 的
STRICT_TRANS_TABLES模式下,向NOT NULL列插入''是允许的;但插入NULL会报错 - 从 CSV 导入时,缺失字段常被解析为
NULL,而空字段(,,)可能是'',需预处理统一
真正麻烦的不是记不住规则,而是同一个字段在应用层、ORM 层、DB 层、迁移脚本里可能被不同方式初始化或校验——NULL 和 '' 看似微小,一旦混用,查数、统计、导出全会偏移。










