https://leetcode.com/problems/exchange-seats/
Table: Seat
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| student | varchar |
+-------------+---------+
id is the primary key (unique value) column for this table.
Each row of this table indicates the name and the ID of a student.
The ID sequence always starts from 1 and increments continuously.
Write a solution to swap the seat id of every two consecutive students. If the number of students is odd, the id of the last student is not swapped.
Return the result table ordered by id in ascending order.
The result format is in the following example.
Example 1:
Input:
Seat table:
+----+---------+
| id | student |
+----+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+----+---------+
Output:
+----+---------+
| id | student |
+----+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+----+---------+
Explanation:
Note that if the number of students is odd, there is no need to change the last one's seat.
내 풀이
SELECT
(CASE
WHEN id % 2 = 0 then id - 1
WHEN id % 2 = 1 AND ID+1 <= (SELECT COUNT(ID) FROM SEAT) then id + 1
else id end ) as id, student
FROM Seat
order by 1
문제점
- SELECT COUNT(ID) 서브쿼리가 전체 테이블을 스캔 (Full Table Scan)
- 테이블이 수백만 건일 경우 성능 이슈
- 서브쿼리가 레코드마다 반복 평가될 수 있음 (DBMS에 따라)
with구문으로 CTE 사용해 성능을 올릴 수 있었다.
WITH cnt AS (
SELECT COUNT(*) AS total FROM Seat
)
다른 사람 풀이
SELECT
id,
CASE
WHEN id % 2 = 0 THEN LAG(student) OVER(ORDER BY id)
ELSE COALESCE(LEAD(student) OVER(ORDER BY id), student)
END AS student
FROM Seat
- 윈도우 함수 기반, DBMS가 내부적으로 최적화 가능
- COUNT() 없이도 짝이 없는 마지막 항목을 자연스럽게 처리 (COALESCE)
- 성능적으로 우수한 DBMS에서는 윈도우 함수가 선형 시간에 동작
논리적 차이
| 항목 | 쿼리 A (CTE + CASE) | 쿼리 B (윈도우 함수) |
|---|
| id 컬럼 | 변형됨 (짝수/홀수 스왑된 id로 출력) | 그대로 유지 (id는 변경 없음) |
| student 컬럼 | 그대로 출력됨 | 짝수/홀수 스왑된 student 출력 |
| 정렬 기준 | 새로 정의된 id 기준으로 정렬 | 원래 id 기준으로 출력됨 |
| 문제 요구 충족 여부 | ✅ 만족 (결과 테이블 id 기준 정렬) | ✅ 만족 (출력 형태만 보면 동일) |
성능 비교
| 요소 | 쿼리 A (CTE + CASE) | 쿼리 B (LAG/LEAD) |
|---|
| 연산 방식 | COUNT 한번 + 각 row에 CASE 분기 | LAG, LEAD 윈도우 함수 |
| 비용 | O(n) + 조건 분기 | O(n) (윈도우 함수는 선형 수행) |
| 최적화 가능성 | 높음 (단순한 CASE + CTE) | 매우 높음 (인덱스 + 순차 접근 가능) |
| 실행 속도 | 적당히 빠름 | 보통 더 빠름 (특히 인덱스가 있을 경우) |
| 가독성 | 비교적 명확 | 초심자에겐 다소 어렵지만 깔끔 |
대용량 데이터에서의 차이
| 상황 | 쿼리 A (CTE 방식) | 쿼리 B (윈도우 함수 방식) |
|---|
| 테이블이 작을 때 | 성능 차이 거의 없음 | 성능 차이 없음 |
| 1M 이상 행일 때 | CASE 조건 분기 비용 ↑ | 윈도우 함수가 더 효율적 |
| 정렬 인덱스가 id에 있을 때 | 빠름 | 더 빠름 (윈도우 함수는 정렬 기반이기 때문) |
| 유지보수 | 조건 명확하므로 쉬움 | 함수 로직 익숙해야 함 |