报表里要把 status 的 0/1/2 换成中文,之前用 case when 写了七行,后来改成一行 decode。语法是 decode(表达式, 值1, 结果1, 值2, 结果2, ..., 默认值)。

select id, decode(status, 0, '待审', 1, '通过', 2, '驳回', '未知') as status_name from orders;

它是等值匹配,不支持大于小于,判断区间还得用 case。参数个数不固定:表达式后面两两成对,最后多出来的那个当默认值。既没写默认值又没匹配上,返回 null。

null 是最常踩的坑

decode 把两个 null 视为相等,这点和等号判断不一样。decode(col, null, '空', '有值') 能正常工作,而 col = null 永远不成立。反过来也有坑:decode(null, null, 1, 0) 返回 1,因为两个 null 被判为相同。想筛出空值,用它比写 is null 省事,但别在业务里依赖这个隐式行为,读代码的人容易看懵。

隐式类型转换也容易出事。decode(1, '1', 'a', 'b') 会返回 a,因为按第一个参数的类型做了转换。数字和字符串字面量混着写时保持类型一致,否则在严格模式下可能直接抛 ORA-01722:invalid number。

和 case 怎么选

  • 纯等值映射、分支多、想写得紧凑,用 decode。
  • 需要范围判断、需要 in 列表、需要嵌套逻辑,用 case when。

decode 还能顺手做排序:order by decode(status, '待处理', 1, '处理中', 2, 3),把业务顺序直接写进排序,不用加辅助字段,也不用改表结构。缺点是这段顺序逻辑埋在 SQL 里,产品改一次流程就得改一次。

参数太多会撞上限

Oracle 对函数参数个数有上限,decode 的参数超过 255 个会报错。真遇到几十个分支,写成 case 或者建一张码表去 join 更清楚。硬堆的话,改一个分支要数半天逗号。

执行计划上两者差别很小,都是同一个函数调用,选哪个看可读性,不看性能。