sql无原生三元运算符,mysql用if()、oracle用case/decode、postgresql/sql server用case;跨库兼容首选标准case表达式,注意类型统一、索引影响及null处理。

SQL里没有原生的 ? : 三元运算符,但所有主流数据库都提供等效替代方案:MySQL 用 IF(),Oracle 用 CASE 或 DECODE,PostgreSQL/SQL Server 用 CASE。选哪个,取决于你用的数据库和表达式复杂度。
MySQL 中直接用 IF() 最接近三元语法
它就是为二选一场景设计的,参数顺序和语义几乎和 condition ? a : b 一致:
-
IF(expr1, expr2, expr3):当expr1为真(非零、非空字符串、非 NULL),返回expr2;否则返回expr3 - 注意
expr1必须是标量值,不能是子查询(除非包在(SELECT ...)里且只返回一行一列) - 隐式类型转换容易踩坑:比如
IF('0', 'yes', 'no')返回'yes'(因为字符串'0'转数字是0,但作为条件时非空即真),而IF(NULL, 'yes', 'no')明确返回'no' - 示例:
SELECT name, IF(age >= 18, 'adult', 'minor') AS status FROM users;
Oracle 中必须用 CASE 或 DECODE,别写 IF
Oracle 的 SQL 层根本没有 IF 函数——那是 PL/SQL 里的控制流语句,不能出现在 SELECT 列表中。常见错误是把 CASE ... END; 写成带分号的语句形式,或误以为 DECODE 能处理范围判断。
-
DECODE(col, val1, res1, val2, res2, else_res)只支持等值匹配,col和每个valN类型要兼容,否则触发ORA-06502 -
CASE WHEN更通用,支持任意布尔表达式:CASE WHEN score > 90 THEN 'A' WHEN score > 80 THEN 'B' ELSE 'C' END - 漏写
ELSE会导致匹配不上的行返回NULL,下游若没加NVL()或COALESCE(),可能引发业务逻辑空值异常 - 别在
SELECT外单独写CASE,它不是独立语句,必须嵌在表达式上下文中
跨数据库兼容写法只能靠 CASE 表达式
如果你的 SQL 要在 MySQL、PostgreSQL、Oracle、SQL Server 之间迁移,IF() 和 DECODE() 都不通用,唯一稳妥的是标准 SQL 的 CASE。
- 简单
CASE(等值):CASE status WHEN 'A' THEN 'Active' WHEN 'I' THEN 'Inactive' ELSE 'Unknown' END - 搜索
CASE(条件):CASE WHEN created_at >= NOW() - INTERVAL '7 days' THEN 'recent' ELSE 'old' END - 所有数据库都支持这两种形式,但 Oracle 对
INTERVAL语法支持有限,得用SYSDATE - 7替代 - 性能上无明显差异,但
CASE在WHERE或ORDER BY中使用时,某些旧版 MySQL 可能无法利用索引,需实测
别在聚合或 WHERE 里滥用条件函数
看起来方便,但容易掩盖真实意图,也影响可读性和优化器判断。
- 在
WHERE中写IF(status = 'paid', 1, 0) = 1不如直接写status = 'paid'—— 多一层函数调用,还可能让索引失效 - 统计类场景常用
SUM(IF(...)),但等价的COUNT(CASE WHEN ... THEN 1 END)更标准,也更易被优化器识别为条件计数 -
DECODE在 Oracle 中虽快,但仅限等值;一旦需要BETWEEN或LIKE,就必须切到CASE WHEN - 最易忽略的一点:所有这些函数返回值的类型由第一个
THEN分支或ELSE决定,后续分支会强制转成该类型——CASE WHEN x=1 THEN 'a' ELSE 2 END在多数数据库里会报错或静默转成字符串










