必须用is null/is not null判断null,因为=、!=等比较运算符与null比较时返回unknown而非true或false,where只保留true行,故column = null永不匹配。

因为 NULL 不是值,而是“缺失”或“未知”的标记,所有涉及它的常规比较和运算都会返回 UNKNOWN 或 NULL,导致条件不成立、表达式崩断、更新静默失败。
WHERE 条件里写 column = NULL 永远不匹配
这是最常见也最容易被忽略的错误。SQL 中 =、!=、 都不能用于判断 NULL —— 它们的结果不是 false,而是 UNKNOWN,而 WHERE 只保留 TRUE 的行。
- 错误写法:
UPDATE users SET status = 'archived' WHERE email = NULL→ 0 行受影响,无报错,但什么都没改 - 正确写法:
UPDATE users SET status = 'archived' WHERE email IS NULL - 注意:哪怕字段类型是 TEXT、JSON 或带索引的列,
IS NULL仍可走索引;而IFNULL(email, '') = ''会强制函数计算,破坏索引
字符串拼接时 memo + m1 遇到 NULL 就整条变 NULL
SQL Server 默认开启 CONCAT_NULL_YIELDS_NULL ON,只要拼接项中有一个是 NULL,整个结果就是 NULL —— 更新语句看似执行成功,实际字段被设为 NULL(或保持原 NULL),不是你想要的拼接结果。
- 现象:
UPDATE table1 SET memo = memo + m1 WHERE uid = '001',若memo是 NULL,则更新后仍是 NULL - 安全写法:
UPDATE table1 SET memo = ISNULL(memo, '') + m1 WHERE uid = '001' - 替代方案(SQL Server):
SET CONCAT_NULL_YIELDS_NULL OFF,但不推荐——它影响整个会话,且 MySQL/PostgreSQL 不支持该开关
触发器里 NEW.field = NULL 判断永远跳过
触发器中的 IF 条件只响应 TRUE,而 NEW.phone = NULL 返回 UNKNOWN,分支直接被忽略,日志不写、校验不拦、默认值不填,还查不出错。
- 错误写法:
IF NEW.phone = NULL THEN ...→ 整个块不会执行 - 必须写成:
IF NEW.phone IS NULL THEN ... - 别用
IF IFNULL(NEW.price, 0) = 0替代 —— 它把真实填了 0 和根本没填(NULL)混为一谈 - BEFORE INSERT 触发器中慎用
OLD.field,因为 OLD 不存在,IFNULL(NEW.name, OLD.name)会报错
MySQL 中 SET column = NULL 实际存成空字符串
某些 MySQL 配置(尤其是低版本或特定 SQL_MODE)下,显式赋 NULL 可能被静默转为空字符串,尤其当字段有默认值或被声明为 NOT NULL 但允许隐式转换时。
- 现象:
UPDATE users SET age = NULL WHERE id = 1执行后查出来是''或0,不是 NULL - 可靠写法:
UPDATE users SET age = DEFAULT WHERE id = 1(前提是该字段定义了DEFAULT NULL) - 更稳妥的做法:先确认字段定义:
SHOW COLUMNS FROM users LIKE 'age',检查 Null 列是否为 YES,Default 是否为 NULL - 插入时同理:
INSERT INTO users (name, age) VALUES ('Tom', DEFAULT)比VALUES ('Tom', NULL)更可控
真正麻烦的不是语法记不住,而是错误不报、行为静默、结果难验证 —— 很多时候你得靠 SELECT IS NULL 手动核对,而不是依赖 affected_rows 或日志输出。











