CASE WHEN 严格从上到下求值,遇首个TRUE条件即返回对应THEN值,后续分支不执行;但THEN/ELSE表达式仅在被选中时求值,不同数据库对短路的支持程度存在差异。
SQL 标准规定 CASE 表达式必须按书写顺序逐个判断 WHEN 条件,一旦某个条件求值为 TRUE(注意:不是非空或非零),就立即返回其 THEN 子句的值,后续 WHEN 不再计算。这本质上就是短路求值。
常见误解是认为“所有条件会并行预计算”,其实不会——数据库引擎会在运行时跳过后续分支。但要注意:这个短路只作用于条件判断逻辑本身,不保护 THEN 或 ELSE 中的表达式提前执行(见下一条)。
WHEN 条件都为 TRUE,只取第一个匹配项,其余忽略NULL 与任何值比较(如 col = NULL)结果为 UNKNOWN,不触发该分支;要用 IS NULL 显式判断LENGTH(col))时,仅当该分支被选中才会执行,可用来规避空值报错很多人误以为把危险操作(比如除零、JSON 解析、类型转换)塞进 THEN 就能靠短路避免报错。实际上,这些表达式确实不会在未命中分支时执行——但前提是:它们**不被优化器提前展开或预编译失败**。
不同数据库行为有差异:
THEN 内部表达式完全不执行THEN/ELSE 分支做类型推导甚至预执行检查,导致 1/0 报错即使该分支永远不走THEN 中的 PL/SQL 函数仍会做语法校验,但运行时短路有效验证方式很简单:
SELECT CASE WHEN 1=0 THEN 1/0 ELSE 42 END;—— 正常返回
42 才说明当前数据库支持分支级短路。
当你在单个 WHEN 子句里写复杂逻辑,比如 WHEN col IS NOT NULL AND JSON_EXTRACT(col, '$.id') > 10,那么即使 col IS NOT NULL 为 FALSE,部分数据库(尤其是 MySQL)可能仍会尝试解析 JSON_EXTRACT 并抛出语法错误——因为 JSON 函数要求参数为合法 JSON 字符串,而 NULL 或非 JSON 值会导致早期失败。
CASE,先确保输入安全:CASE WHEN col IS NOT NULL THEN
CASE WHEN col REGEXP '^\\{.*\\}$' THEN JSON_EXTRACT(col, '$.id') > 10 ELSE FALSE END
ELSE FALSE ENDWHEN 中直接调用可能崩溃的函数;优先用标量判断(IS NULL、REGEXP、LENGTH)做过滤COALESCE 或 NULLIF 预处理参数,比依赖短路更可控有人试图写 WHERE CASE WHEN type='json' THEN JSON_VALID(content) ELSE TRUE END 来动态过滤,这看似聪明,但实际风险很大:
JSON_VALID(content) 应用到所有行,再套 CASE,导致非 json 类型数据报错
JSON_VALID 在非字符串输入上仍可能返回 NULL 而非 FALSE,使整个条件变为 UNKNOWN,被 WHERE 当作不匹配(符合预期),但语义已模糊WHERE (type = 'json' AND JSON_VALID(content)) OR type != 'json'
真正需要动态类型处理时,应优先考虑生成列、物化视图或应用层分流——SQL 的短路不是防错保险丝,只是执行路径的节流阀。