参考原文:https://zhuanlan.zhihu.com/p/110198759?from_voters_page=true
case when
推荐学习书籍:1、SQL
基础教程 6-3 2、SQL
进阶教程 1-1
case when
是SQL
语法中提供的标准的条件分支。
条件分支在MYSQL
中即为IF
函数,不同的数据库都会提供自己的一些函数,但是CASE WHEN
更加通用。
CASE语句的两种写法
1、搜索CASE表达式
(只会这一种方式即可)
CASE
WHEN <求值表达式> THEN
<表达式 1 >
WHEN <求值表达式> THEN
<表达式 2 >
ELSE
<表达式>
END
<求值表达式>
:一般为字段 【=、>、<、in、等】如 字段 = "1"
<表达式1>
: 一般为字段或者字符串或者数值等。
2、简单CASE表达式
CASE <表达式>
WHEN <表达式> THEN
<表达式>
WHEN <表达式> THEN
<表达式> ELSE <表达式>
END
注:
- ELSE 可以不写,默认返回null
- end 不可以忘记
- 当一个case子句中有多个判断逻辑时、字段类型需要一致
- 当一个case子句中有多个判断逻辑时、第一个为真的结果会被输出
- 每一个case子句只输出一个结果
case 执行逻辑
case 应用
1、添加列
现有学生表一张
先在需要根据生日列 **生成新的一列 **
:显示90后,00后,10后
代码:
SELECT
s_name,
s_birthday,
CASE
WHEN YEAR ( s_birthday ) >= 1990 AND YEAR ( s_birthday ) < 2000
THEN "90后"
WHEN YEAR ( s_birthday ) >= 2000 AND YEAR ( s_birthday ) < 2010
THEN "00后"
WHEN YEAR ( s_birthday ) >= 2010 AND YEAR ( s_birthday ) < 2020
THEN "10后"
ELSE "未知"
END AS "阶段"
FROM
student;
显示结果:
2、行转为列
现统计了学生的总成绩
。
先在想将赵雷和李云的总成绩展示成:
可以输入以下代码:
SELECT SUM
( CASE WHEN s_name = "李云" THEN score ELSE 0 END ) AS "李云",
SUM ( CASE WHEN s_name = "赵雷" THEN score ELSE 0 END ) AS "赵雷"
FROM
score
A INNER JOIN student b ON A.s_id = b.s_id;
3、实现分组统计
一般我们都使用group by
来实现分组统计,但是有的时候需要对字段先分组再统计。
比如我们想知道成绩表现为不及格、良、优秀的课程数分别是多少
3.1 实现人次的分组统计
SELECT
CASE
WHEN
score < 60 THEN "不及格" WHEN score >= 60
AND score < 85 THEN "良" WHEN score >= 85 THEN
"优秀" ELSE "未知"
END AS "阶段",
COUNT ( * ) AS "人次"
FROM
score
A INNER JOIN student b ON A.s_id = b.s_id
GROUP BY
CASE
WHEN score < 60 THEN "不及格" WHEN score >= 60
AND score < 85 THEN "良" WHEN score >= 85 THEN
"优秀" ELSE "未知"
END;
因为每个人会参加多门课程,所以当使用count(*)
的时候,就是对于人次计算的,学生是没有去重的。
3.2 实现人数的分组统计
SELECT
CASE
WHEN
score < 60 THEN "不及格" WHEN score >= 60
AND score < 85 THEN "良" WHEN score >= 85 THEN
"优秀" ELSE "未知"
END AS "阶段",
COUNT ( DISTINCT A.s_id ) AS "包含人数"
FROM
score
A INNER JOIN student b ON A.s_id = b.s_id
GROUP BY
CASE
WHEN score < 60 THEN "不及格" WHEN score >= 60
AND score < 85 THEN "良" WHEN score >= 85 THEN
"优秀" ELSE "未知"
END;
这里使用里count(DISTINCT a.s_id)
对学生进行了去重。
3.3 group by分组中使用别名
SELECT
CASE
WHEN
score < 60 THEN "不及格" WHEN score >= 60
AND score < 85 THEN "良" WHEN score >= 85 THEN
"优秀" ELSE "未知"
END AS TYPE,
COUNT ( * )
FROM
score
A INNER JOIN student b ON A.s_id = b.s_id
GROUP BY
TYPE;
更加SQL
执行顺序,是不应该使用别名的,但是在某些,比如MYSQL
中执行时会先扫描select
后的字段,所以实际执行是可以实现的。
4、透视表方式展示
case
表达式可以实现sql
像excel
透视表类似的功能。
比如我想知道每门课程,学生成绩的分别情况
可以使用下方代码进行完成
SELECT
c_id,
SUM ( CASE WHEN score < 60 THEN 1 ELSE 0 END ) AS "不及格",
SUM ( CASE WHEN score >= 60 AND score < 85 THEN 1 ELSE 0 END ) AS "良",
SUM ( CASE WHEN score >= 85 THEN 1 ELSE 0 END ) AS "优秀"
FROM
score
A LEFT JOIN student b ON A.s_id = b.s_id
WHERE
c_id IS NOT NULL
GROUP BY
A.c_id;
case 执行逻辑
1、没有group by 的聚合
上面知识点 行转为列。
代码如下:
SELECT SUM
( CASE WHEN s_name = "李云" THEN score ELSE 0 END ) AS "李云",
SUM ( CASE WHEN s_name = "赵雷" THEN score ELSE 0 END ) AS "赵雷"
FROM
score
A INNER JOIN student b ON A.s_id = b.s_id;
结果为
我们在语句中使用了聚合函数,这个聚合函数使得数据展示为一行。如果不使用会如何?
数据会以每一行的形式展示。
因为SQL
在执行完语句后会逐行对数据进行计算。
2、有group by 的汇总数据
接着上面来讲。
这里有个问题,既然用group by
了,为何还要使用SUM
。(这里主要是在mysql5.7
以下会遇到这样的问题)
我就在实际的统计中,遇到了这样的问题。
因为自己的库装的是mysql5.8
所以这样不符合规范的代码是运行不了的,因为要修改配置比较麻烦,我这里就手动写出他的
| c_id | 不及格 | 良 | 优秀 | | --- | --- | --- | --- | | 01 | 1 | 0 | 0 | | 02 | 0 | 1 | 0 | | 03 | 1 | 0 | 0 |
这里就会出现每行只有一个结果。
SELECT
c_id,
CASE
WHEN score < 60 THEN 1 ELSE 0 END AS "不及格", CASE WHEN score >= 60
AND score < 85 THEN 1 ELSE 0 END AS "良", CASE WHEN score >= 85 THEN
1 ELSE 0
END AS "优秀"
FROM
score
A LEFT JOIN student b ON A.s_id = b.s_id
WHERE
c_id IS NOT NULL
GROUP BY
A.c_id;
因为有groupby
的存在,很容易导致计算错误还,看不错来,这为一个小坑。
这里关于SQL
的执行顺序还需要单独再进行一章。