# 图解面试题：行列互换问题，怎么办？

![](/files/-MUseFcXalJxbV5iYUps)

**【题目】**

下面是表名为 cook 的表

![](/files/-MUseNVy4mTFVWBTDtBs)

要求查询结果如下：

![](/files/-MV5enowk1wqSQn9KFLI)

**【解题思路】**

电影《女男变错身》中是男女互换身份

![](/files/-MV5esuCzN_zRGSW6w_c)

这个题其实也是 “互换身份”，叫做行列互换问题，就是将一维表转化为二维表。

![](/files/-MV5eyBZGwZ42DJX6Oxp)

![](/files/-MV5f1j5S9UWgJq6uNbp)

**1. 输出行列互换的表结构**

可以看出，需要输出的有 5 列，其中只有 “年” 这一列是表 cook 中原有的，其他 4 列（也就是 2-5 列：m1 对应的是 1 月份、m2 对应的是 2 月份、m3 对应的是 3 月份、m4 对应的是 4 月份）需要自己创建。

![](/files/-MV5fNBRYTefZW0llr3D)

```sql
select 年,m1,m2,m3,m4
from cook;
```

可以看出查询结果和目标表的列名结构一样，但是 2-5 列（m1、m2、m3、m4）的值不是题目要求的：

![](/files/-MV5fRBCRi3k-wNPkShh)

**2.如何将 2-5 列的值替换成对应的值？** &#x20;

可以用 case 语句进行条件判断来替换。

![](/files/-MV5fUwHx4t9D_fGdMgR)

年份和月份匹配，则为对应值，不匹配则为 0。

```sql
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。

![](/files/-MV5fYQytNYjJDLALWkj)

第二行是 2009 年 2 月份（m2）的值，而其他三列的值为 0。其他行以此类推。

![](/files/-MV5fbzsR22hG2O5kiCx)

又向目标接近了一步，但是多出来的 0 值，怎么办？

**3.去掉 0 值，简化表格的行数**

可以使用分组汇总来实现。按 “年” 分组（group by），然后用汇总函数（max）取出每组非零的值 (也就是这个案例中的某年某月对应的数值)。

```sql
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 的运行过程如下：

![](/files/-MV5fghJQUXaPDgIR-PY)

![](/files/-MV5fncpsZOR7JToDr_Y)

这样我们就得到了目标表 (行列互换)。

**【本题考点】**

1.考查用 case 语句进行数据替换，和条件判断

![](/files/-MV5fUwHx4t9D_fGdMgR)

2.遇到行列互换的问题，可以用下面的万能模版来解决。

![](/files/-MV5fsJlyOjOtvTaF0e2)

```sql
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;
```

**【举一反三】**

下面是学生的成绩表 (表名：成绩表，列名：学号，课程，成绩)

![](/files/-MV5g0vyPRZ0JSPs01GA)

使用 sql 语句实现将该表行转化为下面的表结构：

![](/files/-MV5gAz2BfPY5kxS56oa)

参考答案：

```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 学号;
```

输出结果：

![](/files/-MV5gAz2BfPY5kxS56oa)

推荐：[如何从零学会 sql？](http://mp.weixin.qq.com/s?__biz=MzAxMTMwNTMxMQ==\&mid=2649247566\&idx=2\&sn=5af748b677eb72028764dde0577675fb\&chksm=835fc77eb4284e68e8cfe3f08c5a671b9e080b2651f20b40b1c793ffda4042ae43ad8f35a755\&scene=21#wechat_redirect)

![](/files/-MV5hNY7pSxAbHfvSae1)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://houzidata.gitbook.io/sql/di-3-zhang-duo-biao-cha-xun/hang-lie-hu-huan-wen-ti-zen-me-ban-song-ni-yi-ge-wan-neng-mo-ban.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
