最常见原因是字段定义为 NOT NULL,数据库静默转为默认值(如空字符串或0)而非报错;需查 INFORMATION_SCHEMA.COLUMNS 确认 IS_NULLABLE=YES,否则须 ALTER TABLE 修改为允许 NULL。

UPDATE SET column = NULL 为什么没生效?
最常见的情况不是语法错,而是字段本身不允许为 NULL。MySQL 或 PostgreSQL 不会报错,而是静默转成默认值(比如空字符串、0),看起来像“没更新”。
确认方式只有一条:查 INFORMATION_SCHEMA.COLUMNS:
SELECT COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table' AND COLUMN_NAME = 'your_column';
IS_NULLABLE 必须是 YES 才能真正写入 NULL;如果是 NO,得先 ALTER TABLE ... MODIFY COLUMN ... NULL。
- WHERE 条件没匹配到行 →
Rows affected: 0,但无提示 - 事务未提交,或连接关闭了自动提交
- 触发器拦截或重写了赋值逻辑
UPDATE WHERE column IS NULL 的写法陷阱
想批量把 NULL 改成默认值,必须用 IS NULL,写成 = NULL 永远不匹配——因为 NULL 不参与任何等值比较,结果恒为 UNKNOWN。
正确写法只有这一种:
UPDATE users SET phone = '未登记' WHERE phone IS NULL;
错误写法(无效):
UPDATE users SET phone = '未登记' WHERE phone = NULL; -- 永远 0 行影响
- 别依赖
COALESCE(phone, '未登记')直接套在 UPDATE 的 SET 里——它会重写所有行,包括非 NULL 行,浪费 I/O 并可能触发冗余日志 - 需要差异化赋值时(如 gender=NULL→'U',amount=NULL→0.00),分开写多条语句比硬塞 CASE 更安全清晰
大表更新 NULL 值时锁表卡死怎么办?
几百万行的表执行 UPDATE ... WHERE column IS NULL,容易长时间持有行锁甚至升级为表锁,阻塞读写。
分批更新是唯一稳妥做法:
- 利用主键或有索引的字段切片:
UPDATE orders SET status = 'pending' WHERE status IS NULL AND id BETWEEN 10000 AND 20000; - 每次更新后加
SLEEP(0.1)(MySQL)或短暂停顿,缓解系统压力 - 避免在业务高峰期执行;优先在从库验证逻辑,再上主库
注意:DEFAULT 约束对已有 NULL 行完全无效,它只影响新插入数据。存量清理必须靠 UPDATE。
NULL 和空字符串、0 在业务逻辑里不能混用
把原本该是 NULL 的字段误设成 '' 或 0,后续 WHERE column IS NULL 就再也查不到它了——这是线上排查中最难回溯的一类隐性问题。
关键区别:
-
NULL表示“未知/不适用”,参与聚合时被COUNT(column)忽略,但COUNT(*)计数 -
''或0是明确值,会被所有统计函数计入 - 索引中 NULL 单独存储,部分数据库对
IS NULL查询可走索引,但= ''是另一回事
字段设计阶段就要定清楚:该存“无意义”还是“有意义的空”,一旦选错,后期清洗成本远高于初期决策。

















