문제 설명
운전자별 운행 기록이 저장된 데이터에서 상반기(1~6월)와 하반기(7~12월)의 평균 연비를 비교하는 문제였다.
여기서 연비는 단순히 주행거리나 연료 사용량의 평균이 아니라,
연비 = distance_km / fuel_consumed
로 계산된다.
구해야 하는 것은 다음과 같다.
- 운전자별 상반기 평균 연비
- 운전자별 하반기 평균 연비
- 연비 향상률
- 상반기와 하반기 모두 운행 기록이 있는 운전자만 포함
- 연비가 향상된 운전자만 출력
출력 컬럼
- driver_id
- driver_name
- first_half_avg
- second_half_avg
- efficiency_improvement
이 문제는 단순 집계 문제가 아니라 기간별 성과 비교 문제에 해당한다.
내가 처음 생각한 접근
처음에는 상반기 데이터를 t1, 하반기 데이터를 t2로 나누어 Self Join 방식으로 접근했다.
생각한 흐름은 다음과 같았다.
상반기 데이터 추출
↓
하반기 데이터 추출
↓
같은 운전자끼리 JOIN
↓
평균 연비 계산
↓
차이 계산
처음에는 꽤 자연스러운 접근처럼 보였다.
왜냐하면
상반기
vs
하반기
를 비교해야 하므로 두 집합을 연결해야 한다고 생각했기 때문이다.
내가 헷갈렸던 부분
1. Self Join을 하면 안 되는 이유
처음에는
trips t1
JOIN trips t2
ON t1.driver_id = t2.driver_id
형태로 작성했다.
하지만 이 방식은 큰 문제가 있다.
예를 들어 어떤 운전자의 기록이
상반기 3건
A
B
C
하반기 2건
D
E
라면
JOIN 결과는
A-D
A-E
B-D
B-E
C-D
C-E
총 6행이 된다.
즉
상반기 건수 × 하반기 건수
만큼 데이터가 증폭된다.
처음에는 같은 운전자끼리만 JOIN되니까 괜찮다고 생각했는데,
실제로는 기간 비교 문제를 Self Join으로 풀면 데이터가 불필요하게 중복 생성될 수 있다는 점을 배웠다.
2. 평균 거리 ÷ 평균 연료는 평균 연비가 아니다
처음에는
AVG(distance_km)
AVG(fuel_consumed)
를 각각 구한 뒤
AVG(distance_km)
/ AVG(fuel_consumed)
를 하면 되지 않을까 생각했다.
하지만 문제에서 요구한 것은
운행별 연비
↓
평균
이다.
즉
AVG(distance_km / fuel_consumed)
가 되어야 한다.
예를 들어
거리 / 연료
| 100 | 10 |
| 100 | 20 |
연비는
10
5
이므로
평균 연비는
(10 + 5) / 2
= 7.5
이다.
하지만
AVG(거리)=100
AVG(연료)=15
100/15
= 6.67
이 된다.
처음에는 비슷해 보였지만 전혀 다른 계산이라는 것을 알게 되었다.
3. 향상량과 향상률은 다르다
처음에는
second_half_avg
-
first_half_avg
를 계산했다.
하지만 문제는
향상량
이 아니라
향상률
을 요구했다.
즉
(하반기 평균 연비 - 상반기 평균 연비)
/
상반기 평균 연비
가 되어야 한다.
문제를 읽을 때 "차이"와 "비율"을 구분하는 습관이 중요하다는 것을 느꼈다.
질문하며 이해한 내용
질문
왜 Self Join이 문제일까?
답변
상반기 N건, 하반기 M건이면 N×M 행이 생성된다.
내가 이해한 내용
기간 비교 문제에서는 JOIN보다 조건부 집계를 먼저 의심해야 한다.
질문
왜 AVG(distance) / AVG(fuel)이 안 될까?
답변
문제는 "평균 연비"를 요구하기 때문이다.
내가 이해한 내용
평균의 순서가 중요하다.
AVG(distance/fuel)
≠
AVG(distance)/AVG(fuel)
질문
이 문제는 어떤 유형일까?
답변
기간별 성과 비교 문제
내가 이해한 내용
상반기 vs 하반기
전년 vs 올해
프로모션 전 vs 후
A/B 테스트 전 vs 후
유형은 거의 같은 패턴으로 풀린다.
최종 해결 방법
1단계. 운전자별 데이터 모으기
운전자와 운행 기록을 연결한다.
2단계. 상반기 연비 계산
상반기 기록만 대상으로
distance_km / fuel_consumed
를 계산하고 평균을 구한다.
3단계. 하반기 연비 계산
동일한 방식으로 하반기 평균 연비를 구한다.
4단계. 상반기와 하반기 기록이 모두 있는 운전자만 남긴다
한쪽 기록만 있으면 비교 자체가 불가능하기 때문이다.
5단계. 향상률 계산
상반기 대비 얼마나 좋아졌는지 계산한다.
6단계. 향상된 운전자만 출력
연비 향상률이 0보다 큰 경우만 남긴다.
내가 작성한 쿼리
WITH a as (
SELECT
t.driver_id,
d.driver_name,
AVG(
CASE
WHEN MONTH(trip_date) BETWEEN 1 AND 6
THEN distance_km / fuel_consumed
END
) avg_km_1,
AVG(
CASE
WHEN MONTH(trip_date) BETWEEN 7 AND 12
THEN distance_km / fuel_consumed
END
) avg_km_2
FROM drivers d
JOIN trips t
ON d.driver_id = t.driver_id
GROUP BY
t.driver_id,
driver_name
)
SELECT
driver_id,
driver_name,
ROUND(avg_km_1,2) AS first_half_avg,
ROUND(avg_km_2,2) AS second_half_avg,
ROUND(avg_km_2 - avg_km_1,2) AS efficiency_improvement
FROM a
WHERE avg_km_1 IS NOT NULL
AND avg_km_2 IS NOT NULL
AND avg_km_2 - avg_km_1 > 0
ORDER BY efficiency_improvement DESC,
driver_name;
핵심 SQL 개념 정리
CASE WHEN inside AVG()
정의
조건을 만족하는 데이터만 평균 계산
왜 사용하는가
상반기 평균과 하반기 평균을 한 번에 계산할 수 있기 때문이다.
실무 활용
- 월별 KPI
- 분기별 매출
- 사용자 세그먼트 비교
면접 포인트
기간별 집계 문제에서 매우 자주 등장하는 패턴이다.
함수 비교 정리
Self Join vs Conditional Aggregation
내가 처음 사용한 방법
t1
JOIN
t2
최종 접근
AVG(
CASE WHEN ...
)
차이
Self Join :
N × M 행 생성 가능
Conditional Aggregation
데이터 증폭 없음
왜 조건부 집계가 더 적절했는가
이 문제는
상반기 데이터
vs
하반기 데이터
를 비교하는 문제이지
상반기 행
vs
하반기 행
를 연결하는 문제가 아니었기 때문이다.
AVG(distance/fuel) vs AVG(distance)/AVG(fuel)
내가 고민했던 방식
AVG(distance)
/ AVG(fuel)
정답 방식
AVG(distance/fuel)
왜 정답이 더 적절한가
문제는 평균 연비를 요구했기 때문이다.
평균 거리와 평균 연료를 이용한 계산은 다른 값이 된다.
오늘 배운 점
기간 비교 문제를 무조건 Self Join으로 접근하면 데이터가 중복 생성될 수 있다.
조건부 집계를 이용하면 훨씬 간단하고 안정적으로 해결할 수 있다.
다음에 같은 문제를 만나면
기간별 평균 비교 문제는 먼저
CASE WHEN + GROUP BY
를 떠올린다.
핵심 한 줄 요약
같은 그룹의 기간별 성과를 비교하는 문제는 Self Join보다 CASE WHEN + 조건부 집계 + GROUP BY 패턴으로 접근하는 것이 가장 안전하고 직관적이다.
'TIL' 카테고리의 다른 글
| [TIL173] leetcode - Find Stores with Inventory Imbalance (0) | 2026.06.25 |
|---|---|
| [TIL172] leetcode - Find Overbooked Employees (0) | 2026.06.25 |
| [TIL170] leetcode - Find COVID Recovery Patients (0) | 2026.06.24 |
| [TIL169] HackerRank - Type of Triangle (0) | 2026.06.24 |
| [TIL168] solvesql - 세 명의 사용자가 서로 친구인 관계 찾기 (Triangle 관계 탐색) (0) | 2026.06.23 |