IF @var = NULL永远不进分支,因为SQL三值逻辑中该比较恒返回UNKNOWN,而IF仅执行TRUE分支;正确写法是用IS NULL或结合OR处理。

IF 条件里写 @var = NULL 为什么永远不进分支
因为 SQL 的三值逻辑中,@var = NULL 永远返回 UNKNOWN,而 IF 只响应 TRUE;UNKNOWN 和 FALSE 都被跳过。这不是 bug,是标准行为。
常见错误写法:IF @status = 'active' BEGIN ... END → 当 @status 是 NULL 时,整个表达式为 UNKNOWN,分支完全不执行。
正确做法取决于业务意图:
- 只想处理明确等于
'active'的情况:用IF @status = 'active'(无需额外判断) - 想把
NULL视为一种有效状态并统一处理:加OR @status IS NULL - 想单独捕获
NULL:用IF @status IS NULL
WHERE 中参数为 NULL 时如何跳过该条件
典型场景是可选搜索字段,比如前端传了 @name 但没传 @age,后端希望只按 name 过滤,age 条件自动失效。
安全写法是把“参数为空”和“字段匹配”拆成两个独立逻辑,用 OR 连接:
WHERE (@name IS NULL OR name = @name) AND (@age IS NULL OR age = @age)
千万别用 WHERE name = ISNULL(@name, name) —— 表面简洁,但 ISNULL(@name, name) 会让优化器放弃使用 name 列上的索引,性能可能断崖下跌。
注意:带 DEFAULT NULL 的参数必须放在存储过程参数列表末尾,否则调用时跳过中间参数会报错:expects parameter '@p2', which was not supplied。
计算或拼接时遇到 NULL 导致结果全为 NULL 怎么办
SQL 中任何值与 NULL 做算术、字符串连接或比较,结果几乎总是 NULL。“未知 + 10 = 未知”,不是报错,而是静默传播。
数值清洗必须显式兜底:
- 错误:
SET @total = @price + @discount→ 任一为NULL,@total就是NULL - 正确:
SET @total = COALESCE(@price, 0) + COALESCE(@discount, 0)
字符串拼接同理:
- 错误:
COALESCE(first_name, '') + ' ' + last_name→last_name为NULL,整串变NULL - 正确:
COALESCE(first_name, '') + ' ' + COALESCE(last_name, '')
触发器里尤其危险:CONCAT('ID:', id, '-', name) 中任一字段为 NULL,结果就是 NULL,可能违反 NOT NULL 约束导致插入失败。
IN / NOT IN 里混入 NULL 为什么查不到数据
NOT IN (1, 2, NULL) 等价于 col != 1 AND col != 2 AND col != NULL,最后一项恒为 UNKNOWN,整个 AND 结果必为 UNKNOWN,WHERE 直接丢弃整行。
动态拼接时更隐蔽:如果 @list 来自含 NULL 的临时表,WHERE col NOT IN (@list) 可能返回空结果集,毫无征兆。
替代方案有两个:
- 先清理:
WHERE col NOT IN (SELECT v FROM @temp WHERE v IS NOT NULL) - 换写法:
NOT EXISTS (SELECT 1 FROM @temp t WHERE t.v = col AND t.v IS NOT NULL)
跨库迁移时优先用 COALESCE 而非 ISNULL 或 IFNULL,前者是 SQL 标准且支持多参数;但要注意 COALESCE(@x, 0) 在 decimal 场景下可能隐式升格精度,引发截断——这点容易被忽略,上线前务必验证类型一致性。

















