문제
https://school.programmers.co.kr/learn/courses/30/lessons/151139
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
✍️ 문제 요약
- 대여 시작일을 기준으로 2022년 8월부터 2022년 10월까지 기간 중
- 총 대여 횟수가 5회 이상인 자동차들
- 해당 기간 동안의 월별 자동차 ID 별 총 대여 횟수(컬럼명: RECORDS)
- 월 기준 오름차순, 같다면 자동차 ID 내림차순
- (특정 월의 총 대여 횟수가 0인 경우에는 결과에서 제외)
🔥 내가 작성한 코드
WITH filter AS (SELECT car_id, COUNT(*) AS total_cnt
FROM car_rental_company_rental_history
WHERE start_date BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY car_id
HAVING COUNT(*) >= 5)
SELECT MONTH(start_date) AS month,
f.car_id,
COUNT(*) AS records
FROM car_rental_company_rental_history h
JOIN filter f ON h.car_id=f.car_id
GROUP BY f.car_id
ORDER BY month ASC, f.car_id DESC;
🚨 작성 코드 문제점 및 개선 과정
1. 메인 쿼리(h)에 기간 필터 없이 사용 ➡️ 메인 쿼리(h)에서 기간 외의 행까지 집계에 끼게 될 가능성 있음.
FROM car_rental_company_rental_history h
JOIN filter f ON h.car_id = f.car_id
WHERE h.start_date BETWEEN '2022-08-01' AND '2022-10-31'
2. MONTH(start_date)가 GROUP BY 에 없음 - SELECT 절에 MONTH(start_date) 있어서, 잘못 집계가 됨.
GROUP BY MONTH(h.start_date), f.car_id
▶ CTE 절에 조건에 해당하는 기간(2022년 08월부터 10월까지)과 기간 내 총 대여횟수 5회 이상을 담아둔다.
▶ CTE 절에 기간 필터링을 했더라도, 메인 쿼리에 반드시 해당 기간 조건 필터링을 진행한다. 안하면 잘못 집계된당(!?)!
✅ 개선된 코드
WITH filter AS (SELECT car_id, COUNT(*) AS total_cnt
FROM car_rental_company_rental_history
WHERE start_date BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY car_id
HAVING COUNT(*) >= 5)
SELECT MONTH(start_date) AS month,
f.car_id,
COUNT(*) AS records
FROM car_rental_company_rental_history h
JOIN filter f ON h.car_id=f.car_id
WHERE start_date BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY MONTH(start_date), f.car_id
ORDER BY MONTH(start_date) ASC, f.car_id DESC;
🔍 다른 풀이
1) CTE 2개 패턴 : a. 기간 전체 기준 총합으로 필터(>=5) | b. 기간 내 월별 집계 ➡️ 두 CTE를 JOIN하는 방식 (가독성/안정성 good)
더보기
더보기
# CTE 구문 2개 사용
WITH eligible_cars AS (
SELECT car_id,
COUNT(*) AS total_cnt
FROM car_rental_company_rental_history
WHERE start_date BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY car_id
HAVING COUNT(*) >= 5
),
monthly_counts AS (
SELECT MONTH(start_date) AS month,
car_id,
COUNT(*) AS monthly_records
FROM car_rental_company_rental_history
WHERE start_date BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY MONTH(start_date), car_id
)
# 메인쿼리문
SELECT m.month,
m.car_id,
m.monthly_records AS records
FROM eligible_cars AS e
JOIN monthly_counts AS m ON e.car_id=m.car_id
ORDER BY month ASC, e.car_id DESC;
2) 윈도우 함수 사용
윈도우 함수를 사용하려면 두 단계로 나눠야 한다.
예컨대:
1 . 먼저 월별 집계(월·car_id → monthly_records)를 만든다.
2. 그 결과 위에서 SUM(monthly_records) OVER (PARTITION BY car_id) 를 사용하면 기간 전체 총합(각 행마다 동일하게 붙음)을 얻을 수 있다.
3. 그 값을 WHERE 또는 외부 쿼리에서 필터(>=5)하면 된다.
이 흐름을 한 쿼리에서 억지로 섞으려 하면(네가 한 것처럼) 계산 의도가 꼬인다.
📌 요점: 윈도우는 집계 결과 위에서 다시 계산할 때 유용하고, 바로 원본 위에서 GROUP BY와 섞으면 의도한 총합을 못 만든다.
SELECT
FROM
끝.
너무 어렵네 젠장
😤
'SQL' 카테고리의 다른 글
| [SQL/코드카타] 프로그래머스 - 그룹별 조건에 맞는 식당 목록 출력하기 (4) | 2025.09.19 |
|---|---|
| [SQL/코드카타] 프로그래머스 : 저자 별 카테고리 별 매출액 집계하기 | WITH, JOIN, GROUP BY (1) | 2025.09.17 |
| [SQL/코드카타] 프로그래머스 : 주문량이 많은 아이스크림 조회하기 (0) | 2025.09.15 |