Leetcode换座位SQL解法差异咨询:为何我的SQL仅返回单行?
为什么我的「换座位」SQL解法只返回单行结果?
我来帮你拆解两种解法的核心差异,以及你的代码出错的根本原因。
首先明确问题背景:这是一道互换相邻学生座位的SQL题,输入输出示例如下:
输入
+---------+---------+ | id | student | +---------+---------+ | 1 | Abbot | | 2 | Doris | | 3 | Emerson | | 4 | Green | | 5 | Jeames | +---------+---------+
输出
+---------+---------+ | id | student | +---------+---------+ | 1 | Doris | | 2 | Abbot | | 3 | Green | | 4 | Emerson | | 5 | Jeames | +---------+---------+
两种解法对比
正确的参考解法
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;
你的解法
select (Case when mod(id,2) !=0 and id != count(*) then id + 1 when mod(id,2) !=0 and id = count(*) then id else id - 1 end) as 'id', student from seat order by id;
核心差异与错误原因
1. 聚合函数的执行上下文是关键
- 参考解法:通过
(SELECT COUNT(*) AS counts FROM seat) AS seat_counts创建了一个独立的子查询,这个子查询会先计算出seat表的总行数(示例中是5),然后作为一张只有一行数据的临时表,和原seat表做笛卡尔关联(因为没有关联条件,相当于给原表的每一行都附加了总记录数这个值)。这样每一行记录都能拿到正确的总行数,从而完成每行的CASE判断。 - 你的解法:直接在
CASE表达式里使用了count(*)——这属于无分组的聚合函数调用。SQL语法规定,当你在没有GROUP BY子句的查询中使用聚合函数时,整个表会被当作一个单独的分组处理,最终只会返回一行结果。这就是为什么你的输出只有单行的原因:聚合操作把所有行合并,student字段会随机取一行(这里取了第一行的Abbot),然后基于总记录数计算出对应的新id。
2. 执行逻辑的具体区别
参考解法中,每一行都能获取到总记录数5,所以每条记录的CASE判断都是独立的:
- id=1:奇数且不是最后一行 → 新id=2
- id=2:偶数 → 新id=1
- id=3:奇数且不是最后一行 → 新id=4
- id=4:偶数 → 新id=3
- id=5:奇数且是最后一行 → 新id=5
而你的解法中,count(*)触发了全局聚合,整个查询只能返回一行结果,自然无法得到所有学生的换座结果。
修正你的解法
只需要把总记录数的计算放在独立子查询中,通过CROSS JOIN(或原参考解法的逗号分隔关联)把总记录数附加到每一行即可:
select (Case when mod(id,2) !=0 and id != counts then id + 1 when mod(id,2) !=0 and id = counts then id else id - 1 end) as id, student from seat cross join (select count(*) as counts from seat) as seat_counts order by id;
内容的提问来源于stack exchange,提问作者shuilinger
相关产品推荐
相关产品推荐

