必须在参数参与任何运算或比较前显式判断或兜底,否则null会静默污染后续逻辑;存储过程开头集中校验必填参数是否为null,字符串类参数需额外判空,输出参数也要校验,where中用@p is null or col = @p跳过条件,算术和字符串操作前必须用coalesce或isnull兜底,变量声明后须立即初始化,子查询赋值前决定是否兜底。

必须在参数参与任何运算或比较前就做显式判断或兜底,否则NULL会静默污染后续所有逻辑。
存储过程开头集中校验必填参数是否为NULL
参数为NULL却不处理,最常导致WHERE全表扫描、CONVERT报错、字符串拼接结果变NULL。别等用到才查,也别指望SQL Server自动提醒你漏传。
- 用
IF @param IS NULL THROW,不用= NULL(后者永远不成立) - 字符串类参数要额外判空:
LEN(ISNULL(@name, '')) = 0,防' '或'' - 输出参数也要校验,比如
@result INT OUTPUT若未赋值,调用方收到的是NULL而非0 - 多个参数时,把所有
IF ... THROW堆在BEGIN后第一块,避免遗漏
WHERE中用@p IS NULL OR col = @p跳过条件
这是可选搜索字段的标准写法。写成col = ISNULL(@p, col)或COALESCE(@p, col) = col表面简洁,但会让SQL Server放弃索引。
-
@p IS NULL走索引,col = @p也走索引,OR组合后优化器仍能高效执行 - 如果业务需区分“未传参”和“传了空字符串”,得加分支:
CASE WHEN @p = '' THEN ... WHEN @p IS NULL THEN ... ELSE ... END - 别在同一个表达式里混用
IS NULL和=,比如WHERE (@p IS NULL OR @p = '') AND col = @p——逻辑混乱且易出错
算术和字符串操作前必须用COALESCE或ISNULL兜底
SET @total = @total + @amount只要@amount是NULL,@total立刻变NULL,后面所有计算都失效。
- 统一用
SET @total = @total + COALESCE(@amount, 0),跨库兼容;SQL Server专属场景可用ISNULL(@amount, 0),类型更稳 - 字符串拼接每个字段都要包:
CONCAT('ID:', COALESCE(id, ''), '-', COALESCE(name, '')),漏一个就全NULL -
COALESCE返回最高优先级类型,ISNULL严格按第一个参数类型返回——如果@val是DECIMAL(10,2),ISNULL(@val, 0)仍为DECIMAL,而COALESCE(@val, 0)可能隐式转成INT
变量初始化和子查询赋值要主动控制NULL行为
SELECT col INTO @var FROM t WHERE id = 123查不到时,@var保持旧值不变;而SET @var = (SELECT col FROM t WHERE id = 123)查不到则@var变NULL——两种行为完全不同,必须按需选。
- 声明变量后立刻初始化:
DECLARE @val VARCHAR(50); SET @val = NULL; - 想让子查询没结果时给默认值,直接用
SET @val = COALESCE((SELECT col FROM t WHERE id = 123), 'default') - 触发器里拼接字段前,先确认所有源字段都已
COALESCE,否则INSERT可能因NOT NULL约束失败
最容易被忽略的不是怎么写COALESCE,而是校验顺序和初始化时机:参数校验必须在BEGIN后立刻做,变量声明后必须立刻SET,子查询赋值前必须决定要不要兜底——这些动作一旦延迟,NULL就会开始悄悄扩散。










