做SQL开发这些年,我见过最密集的翻车现场,不是复杂的多表连接,也不是深不见底的窗口函数,而是看起来人畜无害的条件分支。一个CASE WHEN写反了顺序,一条UPDATE忘记写ELSE,结果就是整张表的数据被改得七零八落。SQL里的条件分支,核心就是CASE表达式,以及它衍生出来的各类写法。这篇我把自己在实际项目里积累的用法、坑点和排查思路一次性整理出来,希望能帮你把这块彻底吃透。
如果你刚接触SQL,条件分支可以简单理解成"按条件决定结果":满足A条件给A结果,满足B条件给B结果,都不满足就给兜底结果。它能用在SELECT里做字段加工,也能用在WHERE、UPDATE、HAVING甚至窗口函数里做逻辑控制。这篇会从一条完整的SQL语句,从SELECT到WHERE到GROUP BY再到UPDATE,把条件分支能做的事全部过一遍。
1. CASE WHEN的求值规则:先和普通if-else做个区分
1.1 简单CASE表达式和搜索式CASE的区别
CASE表达式在SQL里有两种写法:一种是简单表达式,一种是搜索式表达式。
简单CASE的写法是CASE后面跟着一个列名,然后WHEN后面写值:
sql复制SELECT
order_id,
CASE order_status
WHEN 1 THEN '待支付'
WHEN 2 THEN '已支付'
WHEN 3 THEN '已发货'
ELSE '未知状态'
END AS status_text
FROM orders;
简单CASE实际上做的是等值匹配,它把CASE后面的列值和每个WHEN后面的值做等号比较。注意这里的等值比较用的是=,不是IS,所以一旦列值是NULL,这个CASE表达式不会匹配任何WHEN,直接落入ELSE分支。
搜索式CASE则是CASE后面不跟列名,WHEN后面写完整的布尔表达式:
sql复制SELECT
order_id,
amount,
CASE
WHEN amount >= 1000 THEN 'A类客户'
WHEN amount >= 500 THEN 'B类客户'
WHEN amount IS NULL THEN '金额未知'
ELSE 'C类客户'
END AS customer_level
FROM orders;
搜索式CASE能处理范围判断、NULL判断、子查询、函数调用,比简单CASE灵活得多。实际开发里我90%的情况都写搜索式CASE,简单CASE多用在枚举状态字段的翻译上。
1.2 短路求值:WHEN子句的执行顺序
CASE表达式从第一个WHEN开始,从上到下逐个判断,一旦某个WHEN条件为TRUE,就返回对应的THEN结果,后面的WHEN直接跳过。这个行为和很多编程语言的if-else if链一样,叫短路求值。
正因为有这个执行顺序,WHEN子句的排列顺序会直接影响结果。举个例子:
sql复制SELECT
order_id,
amount,
CASE
WHEN amount >= 500 THEN '中额'
WHEN amount >= 1000 THEN '高额'
ELSE '低额'
END AS amount_level
FROM orders;
这段SQL逻辑上就是错的。金额1500的订单,先判断amount >= 500为TRUE,直接返回"中额",永远走不到amount >= 1000的分支。这不是数据库的问题,而是CASE求值顺序决定的:条件满足一个就收手,后面的分支爱莫能助。
写完CASE表达式,建议自己心里跑一遍每条数据,确认分支顺序符合业务语义。特别是范围判断,从大到小写或者从小到大写都要有意识,不是怎么顺手怎么来。
1.3 为什么"没有ELSE就返回NULL"这个细节很要命
CASE表达式的ELSE是可选的。不写ELSE,当所有WHEN分支都不满足时,CASE表达式返回NULL。
这个行为在SELECT里做字段加工可能影响不大,最多少一个值。但在UPDATE里就危险了:
sql复制UPDATE orders
SET order_status = CASE
WHEN order_type = 'normal' THEN 1
WHEN order_type = 'vip' THEN 2
END;
如果表里存在order_type既不是'normal'也不是'vip'的行,这条更新会把那行的order_status置成NULL。NULL在业务系统里往往意味着"异常"或"未知",一旦出现,后续查询、统计、展示全都会出问题。
我自己的原则是:凡是UPDATE里用CASE,必须写ELSE保留原值,或者显式处理所有可能的分支。宁愿多写一个ELSE order_status,也不要偷懒留隐患。
注意:CASE表达式里所有THEN返回值的类型必须一致或能隐式转换。如果一条返回字符串,一条返回数字,数据库会做隐式转换,转换失败就直接报错,转换成功也可能影响索引和性能。这个细节放到后面专门讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 最容易踩的三个分支坑:NULL、WHEN顺序、返回类型
2.1 NULL与比较运算符:永远UNKNOWN
SQL里有三值逻辑:TRUE、FALSE、UNKNOWN。NULL参与任何比较运算,结果都是UNKNOWN,既不是TRUE也不是FALSE。
这句话翻译成人话就是:NULL = 1不成立,NULL = '正常'不成立,NULL = NULL同样不成立。NULL和任何值做等值比较,结果都不是TRUE。
所以下面这两个写法,效果完全不一样:
sql复制-- 错误写法:永远不会匹配到NULL
CASE
WHEN order_status = NULL THEN '未知状态'
ELSE '已知状态'
END
-- 正确写法:用
