MySQL,case when你真的会用吗?附避坑指南

199 阅读5分钟

case when 的语法有如下两种:

1 CASE WHEN [expr] THEN [result1]…
  ELSE [default] END
2 CASE [col_name] WHEN [value1/expr1] THEN [result1]…
  ELSE [default] END

注意:

第一种语法最常用,可比较等于、范围的条件。遇到第一个满足条件的即返回,不再往下比较,如果没有满足的条件则返回else里的结果,如果没有else则返回NULL。

第二种语法不常用,只能比较等于的条件。when后面如果是值,则是表示等于的意思,"="可以不用写,遇到满足条件的才返回,如果没有满足的条件则返回else里的结果,如果没有else则返回NULL。when后面如果是表达式,不管when的条件是否满足,都是返回else里的结果,如果没有else则返回NULL。

when后面要么是表达式,要么是值,不然报错。如果是“=‘101’“或者“>=1000” 这样既不是表达式,也不是值,则执行时报错。

表结构:

CREATE TABLE `staff` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(50) NOT NULL COMMENT '姓名',
  `dept_id` varchar(10) DEFAULT NULL COMMENT '部门id',
  `salary` double DEFAULT NULL COMMENT '工资',
  `sex` int(11) DEFAULT NULL COMMENT '性别,1是男生,0是女生',
  `created_time` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='职员表' 

现有记录:

mysql> select * from staff ;
+----+-------+---------+--------+------+---------------------+---------------------+
| id | name  | dept_id | salary | sex  | created_time        | updated_time        |
+----+-------+---------+--------+------+---------------------+---------------------+
|  1 | Tom   | 101     |   2500 |    1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  2 | Tonny | 101     |   3500 |    1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  3 | Bob   | 101     |   3500 |    0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  4 | Rob   | 101     |   4500 |    1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  5 | Sudey | 101     |   5500 |    0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  6 | Sunny | 102     |   5500 |    1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  7 | Sedey | 102     |   3500 |    0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  8 | Bobby | 102     |   4500 |    0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
|  9 | Weedy | 103     |   4500 |    1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
| 10 | Jimme | 104     |   5500 |    0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
+----+-------+---------+--------+------+---------------------+---------------------+
10 rows in set (0.00 sec)

我们想根据salary区分类别:

1. 使用

CASE WHEN [expr] THEN [result1]…
ELSE [default] END

如下语句的结果符合期望:

when后面是表达式

select
name,
salary,
case 
   when  salary >= 5000 then 'T1'
   when  salary >= 4000 then 'T2'
   when  salary >= 3000 then 'T3'
   when  salary >= 2000 then 'T4'
   else 'T5' 
end as salary_level
from staff ;
+-------+--------+--------------+
| name  | salary | salary_level |
+-------+--------+--------------+
| Tom   |   2500 | T4           |
| Tonny |   3500 | T3           |
| Bob   |   3500 | T3           |
| Rob   |   4500 | T2           |
| Sudey |   5500 | T1           |
| Sunny |   5500 | T1           |
| Sedey |   3500 | T3           |
| Bobby |   4500 | T2           |
| Weedy |   4500 | T2           |
| Jimme |   5500 | T1           |
+-------+--------+--------------+
10 rows in set (0.00 sec)

如下语句的结果则不符合期望:

顺序弄反了,是返回第一个符合条件的结果

select
name,
salary,
case 
   when  salary >= 2000 then 'T1'
   when  salary >= 3000 then 'T2'
   when  salary >= 4000 then 'T3'
   when  salary >= 5000 then 'T4'
   else 'T5' 
end as salary_level
from staff ;
+-------+--------+--------------+
| name  | salary | salary_level |
+-------+--------+--------------+
| Tom   |   2500 | T1           |
| Tonny |   3500 | T1           |
| Bob   |   3500 | T1           |
| Rob   |   4500 | T1           |
| Sudey |   5500 | T1           |
| Sunny |   5500 | T1           |
| Sedey |   3500 | T1           |
| Bobby |   4500 | T1           |
| Weedy |   4500 | T1           |
| Jimme |   5500 | T1           |
+-------+--------+--------------+
10 rows in set (0.00 sec)

2. 使用

CASE [col_name] WHEN [value1] THEN [result1]…
ELSE [default] END

如下语句的结果符合期望:

when后面是值

select
name,
salary,
case  salary
   when   2500 then 'T1'
   when   3500 then 'T2'
   when   4500 then 'T3'
   when   5500 then 'T4'
   else 'T5' 
end as salary_level
from staff ;
+-------+--------+--------------+
| name  | salary | salary_level |
+-------+--------+--------------+
| Tom   |   2500 | T1           |
| Tonny |   3500 | T2           |
| Bob   |   3500 | T2           |
| Rob   |   4500 | T3           |
| Sudey |   5500 | T4           |
| Sunny |   5500 | T4           |
| Sedey |   3500 | T2           |
| Bobby |   4500 | T3           |
| Weedy |   4500 | T3           |
| Jimme |   5500 | T4           |
+-------+--------+--------------+
10 rows in set (0.00 sec)

如下语句则报错:

when后面既不是表达式,也不是值

select
name,
salary,
case  salary
   when   >= 2000 then 'T1'
   when   >= 3000 then 'T2'
   when   >= 4000 then 'T3'
   when   >= 5000 then 'T4'
   else 'T5' 
end as salary_level
from staff ;
-- ERROR 1064 (42000): You have an error in your SQL syntax;

3. 使用

CASE [col_name] WHEN [expr1] THEN [result1]…
ELSE [default] END

如下语句不报错,但是结果不符合期望:

when后面是表达式,不管when的条件是否满足,都是返回else里的结果

select
name,
salary,
case  salary
   when   salary=2500 then 'T1'
   when   salary=3500 then 'T2'
   when   salary=4500 then 'T3'
   when   salary=5500 then 'T4'
   else 'T5' 
end as salary_level
from staff ;
+-------+--------+--------------+
| name  | salary | salary_level |
+-------+--------+--------------+
| Tom   |   2500 | T5           |
| Tonny |   3500 | T5           |
| Bob   |   3500 | T5           |
| Rob   |   4500 | T5           |
| Sudey |   5500 | T5           |
| Sunny |   5500 | T5           |
| Sedey |   3500 | T5           |
| Bobby |   4500 | T5           |
| Weedy |   4500 | T5           |
| Jimme |   5500 | T5           |
+-------+--------+--------------+
10 rows in set (0.00 sec)

如下语句不报错,但是结果不符合期望:

when后面是表达式,已经把else语句注释掉了,不管when的条件是否满足,都是返回NULL

select
name,
salary,
case  salary
   when   salary=2500 then 'T1'
   when   salary=3500 then 'T2'
   when   salary=4500 then 'T3'
   when   salary=5500 then 'T4'
   -- else 'T5' 
end as salary_level
from staff ;
+-------+--------+--------------+
| name  | salary | salary_level |
+-------+--------+--------------+
| Tom   |   2500 | NULL         |
| Tonny |   3500 | NULL         |
| Bob   |   3500 | NULL         |
| Rob   |   4500 | NULL         |
| Sudey |   5500 | NULL         |
| Sunny |   5500 | NULL         |
| Sedey |   3500 | NULL         |
| Bobby |   4500 | NULL         |
| Weedy |   4500 | NULL         |
| Jimme |   5500 | NULL         |
+-------+--------+--------------+
10 rows in set (0.00 sec)

以上是本人亲测,之前使用时有些迷惑第二种语法,如今终于明白了。下期分享case when在分组统计中的实际用法。

当前版本:

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.28    |
+-----------+
1 row in set (0.01 sec)

mysql>