【题目】
下面是表名为 cook 的表
要求查询结果如下:
【解题思路】
电影《女男变错身》中是男女互换身份
这个题其实也是 “互换身份”,叫做行列互换问题,就是将一维表转化为二维表。
1. 输出行列互换的表结构
可以看出,需要输出的有 5 列,其中只有 “年” 这一列是表 cook 中原有的,其他 4 列(也就是 2-5 列:m1 对应的是 1 月份、m2 对应的是 2 月份、m3 对应的是 3 月份、m4 对应的是 4 月份)需要自己创建。
select 年,m1,m2,m3,m4
from cook;
可以看出查询结果和目标表的列名结构一样,但是 2-5 列(m1、m2、m3、m4)的值不是题目要求的:
2. 如何将 2-5 列的值替换成对应的值?
可以用 case 语句进行条件判断来替换。
年份和月份匹配,则为对应值,不匹配则为 0。
select 年,
(case 月 when '1' then 值 else 0 end) as m1,
(case 月 when '2' then 值 else 0 end) as m2,
(case 月 when '3' then 值 else 0 end) as m3,
(case 月 when '4' then 值 else 0 end) as m4
from cook;
在这个查询结果中,每一行表示某年某月的某个值。比如第一行是 2009 年 1 月份(m1)的值,而其他三列 m2、m3、m4 的值为 0。
第二行是 2009 年 2 月份(m2)的值,而其他三列的值为 0。其他行以此类推。
又向目标接近了一步,但是多出来的 0 值,怎么办?
3. 去掉 0 值,简化表格的行数
可以使用分组汇总来实现。按 “年” 分组(group by),然后用汇总函数(max)取出每组非零的值 (也就是这个案例中的某年某月对应的数值)。
select 年,
max(case 月 when '1' then 值 else 0 end) as 'm1',
max(case 月 when '2' then 值 else 0 end) as 'm2',
max(case 月 when '3' then 值 else 0 end) as 'm3',
max(case 月 when '4' then 值 else 0 end) as 'm4'
from cook
group by 年;
这个 sql 的运行过程如下:
这样我们就得到了目标表 (行列互换)。
【本题考点】
- 考查用 case 语句进行数据替换,和条件判断
- 遇到行列互换的问题,可以用下面的万能模版来解决。
select A,
-- 第2步,在行列互换结果表中,其他列里的值分别使用case和max来获取
max(case B when 'm' then C else 0 end) as 'm',
max(case B when 'n' then C else 0 end) as 'n'
from cook
-- 第1步,在行列互换结果表中按第1列分组
group by A;
【举一反三】
下面是学生的成绩表 (表名:成绩表,列名:学号,课程,成绩)
使用 sql 语句实现将该表行转化为下面的表结构:
参考答案:
select 学号,
-- 第2步,在行列互换结果表中,其他列里的值分别使用case和max来获取
max(case 课程 when '语文' then 成绩 else 0 end) as 语文成绩,
max(case 课程 when '数学' then 成绩 else 0 end) as 数学成绩
from 成绩表
-- 第1步,在行列互换结果表中按第1列分组
group by 学号;
输出结果:
推荐:如何从零学会 sql?