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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MUse4N3TSeEKYaoq2C4%2F-MUseFcXalJxbV5iYUps%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_1.webp?alt=media\&token=f8e8a555-0910-4572-893e-4b5236f1e44a)

**【题目】**

下面是表名为 cook 的表

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MUse4N3TSeEKYaoq2C4%2F-MUseNVy4mTFVWBTDtBs%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_2.webp?alt=media\&token=76843f1d-5f29-4aad-8258-58677e09dfea)

要求查询结果如下：

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5enowk1wqSQn9KFLI%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_3.webp?alt=media\&token=6078e24d-ba35-4786-8031-12103c9f70aa)

**【解题思路】**

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5esuCzN_zRGSW6w_c%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_4.webp?alt=media\&token=71bfb798-b8a5-4040-a7e6-3417a3a344d6)

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5eyBZGwZ42DJX6Oxp%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_5.webp?alt=media\&token=c4d79fe2-f91f-4262-a083-991e00929bf0)

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5f1j5S9UWgJq6uNbp%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_6.webp?alt=media\&token=d2de84ff-c431-4d5b-85a9-76f9e5de0ce3)

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

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fNBRYTefZW0llr3D%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_7.png?alt=media\&token=e0f9fb11-e0f6-49a3-9c80-8917ba24c910)

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

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fRBCRi3k-wNPkShh%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_8.webp?alt=media\&token=e8312926-31e3-4974-9273-9bbafb6a27a5)

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

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fUwHx4t9D_fGdMgR%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_8_1.webp?alt=media\&token=9b0cc0d3-c4ac-4415-9194-a0130ae91d56)

年份和月份匹配，则为对应值，不匹配则为 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。

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fYQytNYjJDLALWkj%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_9.webp?alt=media\&token=2fe87d9d-3c87-46ce-a954-e2fae4e99706)

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fbzsR22hG2O5kiCx%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_10.png?alt=media\&token=351f26a3-94fc-43d8-8d06-207b84cc2d1d)

又向目标接近了一步，但是多出来的 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 的运行过程如下：

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fghJQUXaPDgIR-PY%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_11.webp?alt=media\&token=0e9c9e1f-805c-48c7-bc7a-b6ab9ff5c49d)

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fncpsZOR7JToDr_Y%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_12.webp?alt=media\&token=e0386785-2101-4cb3-b61d-6f4ca7c793dd)

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

**【本题考点】**

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fUwHx4t9D_fGdMgR%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_8_1.webp?alt=media\&token=9b0cc0d3-c4ac-4415-9194-a0130ae91d56)

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5fsJlyOjOtvTaF0e2%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_13.webp?alt=media\&token=f1629efc-fa01-42ab-b377-f9bd6ad560c4)

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

**【举一反三】**

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5g0vyPRZ0JSPs01GA%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_14.webp?alt=media\&token=9c294a52-1019-477d-a477-db53265e0db4)

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5gAz2BfPY5kxS56oa%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_16.webp?alt=media\&token=0501bf38-87ea-4261-930c-6faf66ea9d51)

参考答案：

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

输出结果：

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5gAz2BfPY5kxS56oa%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_16.webp?alt=media\&token=0501bf38-87ea-4261-930c-6faf66ea9d51)

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

![](https://4109408004-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MTuZ3PxkXf2a7UbRybW%2F-MV5eXXqr-OqTX1MX7LD%2F-MV5hNY7pSxAbHfvSae1%2F%E8%A1%8C%E5%88%97%E4%BA%92%E6%8D%A2%E9%97%AE%E9%A2%98_17.webp?alt=media\&token=c2e69837-97bf-4a24-805a-39bc3343c770)
