case when是sql表达式,用于select/where/order by;pl/sql中仅有case语句(控制流),二者语法、用途严格区分,不可混用,且null判断必须用is null。
case when 是表达式,能用在 select/where/order by 里
pl/sql 里没有独立的“搜索 case 语句”这种东西——你真正遇到的,是两种不同语法:一种是 case when 表达式(返回值),另一种是 case 语句(控制流,类似 if-else)。前者能嵌进 sql 任何允许表达式的位置;后者只能单独成句,不能返回结果。
常见错误现象:SELECT id, CASE WHEN status = 'A' THEN 'Active' END FROM t; 能跑;但有人试图写 SELECT id, CASE status WHEN 'A' THEN 'Active' END FROM t; 却发现报错或结果不对——其实这第二种写法本身合法,但属于“简单 CASE 表达式”,它做的是等值匹配,不支持 >、IS NULL 这类判断。
- 用
CASE WHEN(搜索型):适合带布尔逻辑的判断,比如CASE WHEN score >= 90 THEN 'A' WHEN score >= 80 THEN 'B' ELSE 'C' END - 用
CASE expr WHEN value THEN ...(简单型):只适合单字段等值映射,比如CASE dept_id WHEN 10 THEN 'HR' WHEN 20 THEN 'IT' END - 两者都不能省略
ELSE;没写且条件全不匹配时,返回NULL,不是报错——这点常被忽略,导致空值蔓延
PL/SQL 块里别把 CASE WHEN 当 IF 用
在 PL/SQL 过程或函数中,如果想根据条件执行不同逻辑分支,必须用 CASE 语句(无 WHEN 的独立结构),而不是 CASE WHEN 表达式。后者在 PL/SQL 中只能出现在赋值、RETURN 或 SQL 执行上下文中,不能直接控制流程。
常见错误现象:写成这样会报编译错误 PLS-00103:
DECLARE
v_status VARCHAR2(10) := 'A';
BEGIN
CASE WHEN v_status = 'A' THEN
DBMS_OUTPUT.PUT_LINE('Active');
ELSE
DBMS_OUTPUT.PUT_LINE('Inactive');
END CASE; -- ❌ 语法错误:PL/SQL 不接受这种写法
END;
正确写法是去掉 WHEN,用纯 CASE 语句:
DECLARE
v_status VARCHAR2(10) := 'A';
BEGIN
CASE v_status
WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Active');
ELSE DBMS_OUTPUT.PUT_LINE('Inactive');
END CASE; -- ✅ 合法
END;
-
CASE语句必须有END CASE,不能简写为END - 它不返回值,所以不能用于赋值,比如
v_result := CASE ... END CASE;是非法的 - 如果真需要表达式结果再做逻辑处理,就老实用
IF-ELSIF-ELSE,别硬套CASE
NULL 判断必须显式写 IS NULL,不能用 = NULL
在 CASE WHEN 表达式里,NULL 是特殊值,所有常规比较(=、、!=)对它都返回 UNKNOWN,即不成立。所以即使你写了 WHEN col = NULL THEN ...,这个分支也永远进不去。
使用场景:查报表时要区分 “未填” 和 “填了 N/A”,字段可能是 NULL 或字符串。
- ✅ 正确写法:
CASE WHEN col IS NULL THEN 'Not entered' WHEN col = 'N/A' THEN 'Not applicable' ELSE col END - ❌ 错误写法:
CASE WHEN col = NULL THEN ...—— 这个条件恒为假 - 注意:简单 CASE(
CASE col WHEN NULL THEN ...)根本无法编译,Oracle 直接报错PLS-00363
性能上,CASE WHEN 比 DECODE 略慢但更可读,别为这点差异妥协可维护性
很多人纠结该用 CASE WHEN 还是旧式 DECODE。实测在大多数 OLTP 场景下,两者执行计划几乎一致,CPU 时间差在毫秒级以下。真正影响性能的是嵌套层数和判断字段是否可索引,不是函数选型。
容易踩的坑:
-
DECODE不支持布尔表达式,比如DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown')可以,但DECODE(score > 90, TRUE, 'A', 'F')会报错——因为DECODE第一个参数必须是表达式结果,不能是条件本身 -
CASE WHEN支持任意复杂条件,且各分支类型自动隐式转换(只要最终能统一成一种类型),而DECODE要求所有返回值类型严格一致,否则可能触发意外的类型转换开销 - Oracle 官方文档已明确建议新代码优先用
CASE,DECODE仅保留兼容性
实际项目里,看到有人为了“性能”硬把五层 CASE WHEN 改成 DECODE,结果逻辑出错又花半天调试——不如花十分钟加个注释说明判断逻辑。










