结论:NULL 在 SQL 中参与任何运算或比较均返回 UNKNOWN 或 NULL,导致逻辑失效、计算中断、约束失败;必须用 IS NULL/IS NOT NULL 判断,用 COALESCE 或 ISNULL 显式转换,且须严格区分 NULL 与空字符串。

直接说结论:别用 = NULL 或 IN 判断,也别让 NULL 参与算术运算——它会让整个结果变 NULL,而你可能根本没意识到。
IF 条件里判断 NULL 为什么总不进分支
在存储过程中写 IF @status = 'active',哪怕 @status 是 NULL,这个条件也不会成立,也不会走 ELSE;它压根没被判定为真或假,而是返回 UNKNOWN,等效于跳过。MySQL、SQL Server、PostgreSQL 全都这样。
- 正确写法永远是
IF @status IS NULL或IF @status IS NOT NULL - 如果想统一处理空和非空逻辑,先用
ISNULL(@status, 'unknown')(SQL Server)或COALESCE(@status, 'unknown')(跨库兼容)转成确定值,再比较 - 特别注意触发器场景:
BEFORE INSERT中对NEW.phone做CONCAT('P-', NEW.phone),若phone是NULL,结果就是NULL,可能违反NOT NULL约束导致插入失败
计算字段时 NULL 导致结果全崩
SET @total = @total + @amount; 看似简单,但只要 @amount 是 NULL,@total 就立刻变成 NULL,后续所有基于它的计算都会失效——这不是报错,是静默污染。
- 修复方式不是加 TRY/CATCH,而是提前兜底:
SET @total = @total + ISNULL(@amount, 0); - 聚合场景同理:
SUM(amount)会自动忽略NULL,但AVG(amount)分母只计非空行,容易误导;若业务上“未填=0”,就得用COALESCE(amount, 0)包一层再聚合 - 字符串拼接更危险:
CONCAT(col1, col2)遇到任一NULL就返回NULL;而+运算符(SQL Server)甚至会直接返回NULL,连警告都没有
ISNULL vs COALESCE:选哪个?看数据库和移植性
ISNULL 是 SQL Server 特有函数,只接受两个参数,返回第一个非 NULL 的值,且类型严格继承左操作数;COALESCE 是 SQL 标准函数,支持多参数,返回第一个非 NULL 值,类型按隐式转换规则决定。
- 写跨库兼容代码(比如未来要迁到 MySQL 或 PostgreSQL),必须用
COALESCE(@val, 'default') - SQL Server 内部优化对
ISNULL更友好,但差别极小;真正影响性能的是是否在 WHERE 或 JOIN 条件里用了函数包裹列,比如WHERE COALESCE(status, 'N') = 'Y'会导致索引失效 - 注意陷阱:
COALESCE(@x, 0)和ISNULL(@x, 0)表面一样,但如果@x是DECIMAL(10,2),ISNULL返回仍是DECIMAL(10,2),而COALESCE可能升格为DECIMAL(10,3),引发精度问题
空字符串 '' 和 NULL 必须分开对待
它们语义完全不同:'' 是已知的空字符串,NULL 是未知/缺失。很多业务错误就出在混用上——比如把用户没填手机号当成 '',结果 LEN(phone) = 0 能查到,但 phone IS NULL 查不到。
- 入库前清洗建议:
UPDATE t SET phone = NULL WHERE LTRIM(RTRIM(ISNULL(phone, ''))) = '';先清空字符串再转NULL - 查询时若需同时覆盖两种情况:
WHERE ISNULL(NULLIF(LTRIM(RTRIM(phone)), ''), NULL) IS NULL,或者更直白:WHERE phone IS NULL OR phone = '' - 唯一约束下,多个
NULL是允许的,但多个''会报重复键冲突——这点常被忽略,导致 UNIQUE 索引行为不符合预期
最麻烦的不是不会写 ISNULL,而是忘记它只解决“值替换”,不解决“语义混淆”。NULL 是未知,不是零、不是空、不是假——一旦把它当默认值使,逻辑漏洞就埋进去了。

















