> For the complete documentation index, see [llms.txt](https://houzidata.gitbook.io/sql/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://houzidata.gitbook.io/sql/di-3-zhang-duo-biao-cha-xun/tu-jie-mian-shi-ti-ru-he-jiao-huan-shu-ju.md).

# 图解面试题：如何交换数据？

![](/files/-MUsThH1iz9oIrOjR-qa)

**【题目】**

小明是一所学校的老师，她有一张 “学生表”，平时用来存放座位号和学生的信息。其中，座位号是连续递增的。总的座位数是偶数。

![](/files/-MUsTorXNF85lkTXkpc6)

现在，小明想改变相邻俩学生的座位。你能不能帮她写一个 sql 查来输出想要的结果呢？

示例查询结果如下：

![](/files/-MUsTsw2VGT7MXkLrqLQ)

**【解题思路】**

**第一步：理清换座位的逻辑**

查询目的是改变相邻学生的座位号。为了理清逻辑，在原表中插入一列叫做“奇偶数”，对应表示 “座位号” 的值是 “奇数” 还是“偶数”。

![](/files/-MUsU-GkLaKDtsG1aG6s)

然后比较原始表里的 “座位号” 和交换结果里的“座位号”（[对比分析方法](http://mp.weixin.qq.com/s?__biz=MzAxMTMwNTMxMQ==\&mid=2649246563\&idx=2\&sn=3ffe509999d144d23dec5acc101fc2ef\&chksm=835fc353b4284a45ce01391453fe2fec1b225bbd6bbdb67dd7f304aacdd4f21f60d0b27ba309\&scene=21#wechat_redirect)），可以发现下图的规律。

![](/files/-MUsU3Lt6FpQmTafQzec)

1）如果原来座位号是**奇数**的学生，换座位后，这名学生的座位号变为 “座位号 + 1”**。**

2）如果原来座位号是**偶数**的学生，换座位后，这名学生的座位号变为 “座位号 - 1”**。**

**第二步：如何判断座位号是奇数，还是偶数**

sql 求余函数：mod(n,m) ，返回 n 除以 m 的余数。比如 mod(8,2) 的结果是 0。

如果 n 除以 2 的余数是 0，说明 n 是偶数，否则是奇数。

转换为判断奇数，偶数的 sql 就是：

```sql
case
      when mod(座位号, 2) != 0  then  '奇数'
      when mod(座位号, 2)  = 0  then  '偶数'
end
```

把前面的逻辑写到 sql 里就是：

1）如果原来座位号是**奇数**的学生，换座位后，这名学生的座位号变为 “座位号 + 1”**。**

2）如果原来座位号是**偶数**的学生，换座位后，这名学生的座位号变为 “座位号 - 1”**。**

```sql
case
       when mod(座位号, 2) != 0  then 座位号 + 1
       when mod(座位号, 2)  = 0  then 座位号 - 1
end  as  '交换后座位号'
```

加入 select 字句，就是最好的结果：

```sql
select
      (case
             when mod(座位号, 2) != 0  then 座位号 + 1
             when mod(座位号, 2)  = 0  then 座位号 - 1
      end)  as  '交换后座位号',
      姓名
from 学生表;
```

**【本题考点】**

1. 逻辑思维能力，如何使用对比分析方法发现规律
2. 条件判断语句 case
3. 如何判断奇数和偶数：mod 函数

**【举一反三】**

原始座次表 ‘seat’如下，现需要更换相邻位置学生的座次。

注：该座次表‘seat’共有 5 名学生，第 5 个 座位号是奇数的不变

![](/files/-MUsUBcGaEtwL2Zdj1tH)

查询逻辑和前面一样，但是座位总数是奇数，所以：如果最后一个座位号也是奇数，那么他没有可以交换的座位了，所以最后一个座位号的学生不变。

最后一个座位号，等于表里有多少行，可以用 count(\*) 计算出来

```sql
# 最后一个座位号
select count(*) as counts 
from seat;
```

最后一个座位号作为条件判断使用时，可以使用子查询，以便调用。最终 sql 如下。

```sql
select
    (case
      # 当座位号是奇数并且不是不是最后一个座位号时
        when mod(id, 2) != 0 and counts!= id then id + 1
       # 当座位号是奇数并且是最后一个座位号时，座位号不变
        when mod(id, 2) != 0 and counts = id then id
       # 当座位号是偶数时
        else id - 1
    end) as id2,student
from seat,(select count(*) as counts from seat);
```

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

![](/files/-MUsUxrOfWUjk_0YTCxb)
