
문제
https://school.programmers.co.kr/learn/courses/30/lessons/131532
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 설명
- USER_INFO 테이블과 ONLINE_SALE 테이블에서 년, 월, 성별 별로 상품을 구매한 회원수를 집계하는 SQL문을 작성
- 결과는 년, 월, 성별을 기준으로 오름차순 정렬
- 이때, 성별 정보가 없는 경우 결과에서 제외
정답 코드
SELECT YEAR(O.SALES_DATE) YEAR,
MONTH(O.SALES_DATE) MONTH,
U.GENDER,
COUNT(DISTINCT O.USER_ID) USERS
FROM USER_INFO U JOIN ONLINE_SALE O ON U.USER_ID = O.USER_ID
WHERE U.GENDER IS NOT NULL
GROUP BY YEAR, MONTH, U.GENDER
ORDER BY YEAR, MONTH, U.GENDER
- COUNT(DISTINCT O.USER_ID)
→ 같은 달에 여러 번 구매한 회원도 1번만 카운트됨
→ 회원 수 집계를 정확히 하기 위해 반드시 DISTINCT 필요
개선된 코드 (CTE 활용)
WITH FILTERED_SALE AS (SELECT O.USER_ID,
YEAR(O.SALES_DATE) AS YEAR,
MONTH(O.SALES_DATE) AS MONTH,
U.GENDER
FROM USER_INFO U JOIN ONLINE_SALE O ON U.USER_ID = O.USER_ID
WHERE U.GENDER IS NOT NULL)
SELECT YEAR, MONTH, GENDER,
COUNT(DISTINCT USER_ID) AS USERS
FROM FILTERED_SALE
GROUP BY YEAR, MONTH, GENDER
ORDER BY YEAR, MONTH, GENDER
- 복잡한 조인과 필터가 들어간 경우, CTE를 활용해 중간 단계를 분리하면 쿼리의 가독성과 유지보수성이 향상됨
(참고) 성능 고려 시, DATE_FORMAT 사용 가능 (MySQL)
- 단, 성능 차이가 크지 않은 상황에서는 불필요
SELECT DATE_FORMAT(O.SALES_DATE, '%Y') AS YEAR,
DATE_FORMAT(O.SALES_DATE, '%m') AS MONTH,
U.GENDER,
COUNT(DISTINCT O.USER_ID) AS USERS
...
첫 번째 시도 (실패)
SELECT YEAR(O.SALES_DATE) YEAR,
MONTH(O.SALES_DATE) MONTH,
U.GENDER,
COUNT(*) USERS
FROM USER_INFO U JOIN ONLINE_SALE O ON U.USER_ID = O.USER_ID
WHERE U.GENDER IS NOT NULL
GROUP BY YEAR, MONTH, U.GENDER
ORDER BY YEAR, MONTH, U.GENDER
틀린 이유
- 문제 조건에 따라 동일한 날짜 + 회원 ID + 상품 ID 조합은 중복 없음
- 하지만, 같은 달 안에 동일 회원이 여러 번 구매할 수는 있음
- COUNT(*)는 구매 건수를 세기 때문에, 같은 회원도 여러 번 카운트됨

- 중복 제거된 회원 수 세는 코드 생각해보기 (DISTINCT)
'코딩 테스트 연습 > [프로그래머스][리트코드] MySQL' 카테고리의 다른 글
| [LV.4] String, Date > 자동차 대여 기록에서 장기/단기 대여 구분하기 (1) | 2025.07.01 |
|---|---|
| [LV.4] SELECT > 서울에 위치한 식당 목록 출력하기 (1) | 2025.06.30 |
| [LV.4] GROUP BY > 자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기 ⭐ (2) | 2025.06.26 |
| [LV.4] String, Date > 취소되지 않은 진료 예약 조회하기 ⭐ (1) | 2025.06.25 |
| [LV.4] String, Date > 조건에 부합하는 중고거래 상태 조회하기 (0) | 2025.06.24 |