MySQL换座位

Posted wgchen~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL换座位相关的知识,希望对你有一定的参考价值。

SQL架构

Create table If Not Exists seat(id int, student varchar(255));

insert into seat (id, student) values ('1', 'Abbot');
insert into seat (id, student) values ('2', 'Doris');
insert into seat (id, student) values ('3', 'Emerson');
insert into seat (id, student) values ('4', 'Green');
insert into seat (id, student) values ('5', 'Jeames');

mysql> SELECT * FROM `seat` LIMIT 0, 1000;
+------+---------+
| id   | student |
+------+---------+
|    1 | Abbot   |
|    2 | Doris   |
|    3 | Emerson |
|    4 | Green   |
|    5 | Jeames  |
+------+---------+
5 rows in set (0.00 sec)

题目描述

小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。

其中纵列的 id 是连续递增的,小美想改变相邻俩学生的座位。

你能不能帮她写一个 SQL query 来输出小美想要的结果呢?

示例:

+---------+---------+
|    id   | student |
+---------+---------+
|    1    | Abbot   |
|    2    | Doris   |
|    3    | Emerson |
|    4    | Green   |
|    5    | Jeames  |
+---------+---------+

假如数据输入的是上表,则输出结果如下:

+---------+---------+
|    id   | student |
+---------+---------+
|    1    | Doris   |
|    2    | Abbot   |
|    3    | Green   |
|    4    | Emerson |
|    5    | Jeames  |
+---------+---------+

注意:

如果学生人数是奇数,则不需要改变最后一个同学的座位。

题解

方法一:使用 CASE

算法

对于所有座位 id 是奇数的学生,修改其 id 为 id+1,如果最后一个座位 id 也是奇数,则最后一个座位 id 不修改。对于所有座位 id 是偶数的学生,修改其 id 为 id-1。

首先查询座位的数量。

SELECT
    COUNT(*) AS counts
FROM
    seat

然后使用 CASE 条件和 MOD 函数修改每个学生的座位 id。

mysql> SELECT * FROM `seat` LIMIT 0, 1000;
+------+---------+
| id   | student |
+------+---------+
|    1 | Abbot   |
|    2 | Doris   |
|    3 | Emerson |
|    4 | Green   |
|    5 | Jeames  |
+------+---------+
5 rows in set (0.00 sec)
在 MySQL 中求余函数 MOD(x,y) 返回 x 被 y 除后的余数,MOD() 对于带有小数部分的数值也起作用,
它返回除法运算后的余数。

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 id,
    student
FROM seat,
    (SELECT COUNT(*) AS counts FROM seat) AS seat_counts ORDER BY id ASC;
+------+---------+
| id   | student |
+------+---------+
|    1 | Doris   |
|    2 | Abbot   |
|    3 | Green   |
|    4 | Emerson |
|    5 | Jeames  |
+------+---------+
5 rows in set (0.00 sec)

方法二:使用位操作和 COALESCE()

算法

使用 (id+1)^1-1 计算交换后每个学生的座位 id。

mysql> SELECT id, (id+1)^1-1, student FROM seat;
+------+------------+---------+
| id   | (id+1)^1-1 | student |
+------+------------+---------+
|    1 |          2 | Abbot   |
|    2 |          1 | Doris   |
|    3 |          4 | Emerson |
|    4 |          3 | Green   |
|    5 |          6 | Jeames  |
+------+------------+---------+
5 rows in set (0.00 sec)

然后连接原来的座位表和更新 id 后的座位表。

SELECT
    *
FROM
    seat s1
        LEFT JOIN
    seat s2 ON (s1.id+1)^1-1 = s2.id
ORDER BY s1.id;

+------+---------+------+---------+
| id   | student | id   | student |
+------+---------+------+---------+
|    1 | Abbot   |    2 | Doris   |
|    2 | Doris   |    1 | Abbot   |
|    3 | Emerson |    4 | Green   |
|    4 | Green   |    3 | Emerson |
|    5 | Jeames  | NULL | NULL    |
+------+---------+------+---------+
5 rows in set (0.00 sec)

注:前两列来自表 s1,后两列来自表 s2。

最后输出 s1.id 和 s2.student。但是 id=5 的学生,s1.student 正确,s2.student 为 NULL。因此使用 COALESCE() 函数为最后一行记录生成正确的输出。

SELECT
    s1.id, COALESCE(s2.student, s1.student) AS student
FROM
    seat s1
        LEFT JOIN
    seat s2 ON ((s1.id + 1) ^ 1) - 1 = s2.id
ORDER BY s1.id;

+------+---------+
| id   | student |
+------+---------+
|    1 | Doris   |
|    2 | Abbot   |
|    3 | Green   |
|    4 | Emerson |
|    5 | Jeames  |
+------+---------+
5 rows in set (0.00 sec)

知识点

coalesce 函数返回其参数中第一个非空表达式

COALESCE是一个函数, (expression_1, expression_2, …,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值。如果所有的表达式都是空值,最终将返回一个空值。使用COALESCE在于大部分包含空值的表达式最终将返回空值。

返回其参数中第一个非空表达式


如果想将verfiy_date为空的选出来,通常做法:

select id from table where verify_date is null;

也可以使用如下做法,当verify_date值为空的时候,取过滤条件‘2020-09-06’代替

select id from table where coalesce(verify_date,'2020-09-06')<='2020-09-07'

查询结果

^ 按位异或

按位异或运算

按位异或运算是数学或者计算机中运用到的数据处理的方法。

异或运算

首先异或表示当两个数的二进制表示,进行异或运算时,当前位的两个二进制表示不同则为1 ,相同则为0. 改方法被广泛用来统计一个数的1的位数。

即:
0 ^ 0 = 0 ,
0 ^ 1 = 1,
1 ^ 0 = 1 ,
1 ^ 1 = 0 ,

按位异或的3个特点:

1.) 0 ^ 0 = 0 , 0 ^ 1 = 1, 0异或任何数=任何数。
2.)1 ^ 0 = 1 , 1 ^ 1 = 0 , 1异或任何数=任何数取反。
3.)任何数异或自己 = 把自己置0。

以上是关于MySQL换座位的主要内容,如果未能解决你的问题,请参考以下文章

力扣——换座位(数据库的题

LeetCode:Database 06.换座位

LeetCode(数据库)- 换座位

1041. 考试座位号(15)

L1-005. 考试座位号

每日SQL打卡​​​​​​​​​​​​​​​DAY 10丨换座位难度中等