[프로그래머스] ⭐⭐⭐⭐ 주문량이 많은 아이스크림들 조회하기 (MySQL)
📌 문제 설명
다음은 아이스크림 가게의 상반기 주문 정보를 담은 FIRST_HALF 테이블과 7월의 아이스크림 주문 정보를 담은 JULY 테이블입니다.
FIRST_HALF 테이블 구조는 다음과 같으며, SHIPMENT_ID, FLAVOR, TOTAL_ORDER는 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 상반기 아이스크림 총주문량을 나타냅니다. FIRST_HALF 테이블의 기본 키는 FLAVOR입니다.
| Column name | Type | Nullable |
|---|---|---|
| SHIPMENT_ID | INT | FALSE |
| FLAVOR | VARCHAR(N) | FALSE |
| TOTAL_ORDER | INT | FALSE |
JULY 테이블 구조는 다음과 같으며, SHIPMENT_ID, FLAVOR, TOTAL_ORDER 은 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 7월 아이스크림 총주문량을 나타냅니다. JULY 테이블의 기본 키는 SHIPMENT_ID입니다. JULY테이블의 FLAVOR는 FIRST_HALF 테이블의 FLAVOR의 외래 키입니다. 7월에는 아이스크림 주문량이 많아 같은 맛의 아이스크림이라도 다른 출하 번호를 갖게 되는 경우가 있습니다.
📌 문제
7월 아이스크림 총 주문량과 상반기의 아이스크림 총 주문량을 더한 값이 큰 순서대로 상위 3개의 맛을 조회하는 SQL 문을 작성해주세요.
💻 코드
ver(1) - WITH & UNION ALL 활용 (추천)
두 테이블을 세로로 이어 붙인 뒤, 맛(FLAVOR)별로 그룹화하여 총합을 구하는 직관적인 방식입니다. UNION 대신 중복 제거 과정이 없어 성능이 좋고 데이터 누락 위험이 없는 UNION ALL을 사용했습니다.
WITH ALL_ORDERS AS (
-- FIRST_HALF 테이블의 맛과 주문량 조회
SELECT FLAVOR, TOTAL_ORDER FROM FIRST_HALF
UNION ALL -- 중복을 제거하지 않고 JULY 테이블의 데이터와 세로로 단순히 결합
-- JULY 테이블의 맛과 주문량 조회
SELECT FLAVOR, TOTAL_ORDER FROM JULY
)
SELECT FLAVOR
FROM ALL_ORDERS
GROUP BY FLAVOR -- 결합된 임시 테이블을 아이스크림 맛을 기준으로 그룹화
ORDER BY SUM(TOTAL_ORDER) DESC -- 그룹화된 맛별 총 주문량(SUM)을 내림차순 정렬
LIMIT 3; -- 상위 3개의 결과만 출력
ver(2) - JOIN 활용
실무에서 데이터 테이블을 다룰 때 가장 정석적으로 많이 쓰이는 방식입니다. 7월(JULY) 데이터는 같은 맛이 여러 번 출하될 수 있으므로, 먼저 7월 데이터를 맛별로 합산한 서브쿼리를 만든 후 상반기(FIRST_HALF) 데이터와 조인합니다.
SELECT F.FLAVOR
FROM FIRST_HALF F
JOIN (
-- JULY 테이블은 같은 맛이라도 출하 번호가 다를 수 있으므로, 조인 전에 미리 합산
SELECT FLAVOR, SUM(TOTAL_ORDER) AS JULY_TOTAL
FROM JULY
GROUP BY FLAVOR
) J ON F.FLAVOR = J.FLAVOR -- 맛(FLAVOR)을 기준으로 상반기와 7월 테이블 조인
ORDER BY (F.TOTAL_ORDER + J.JULY_TOTAL) DESC -- 상반기 주문량과 합산된 7월 주문량을 더하여 내림차순 정렬
LIMIT 3; -- 상위 3개만 추출
ver(3) - Window Function (RANK() OVER) 활용
LIMIT 3을 사용하지 않고 윈도우 함수를 활용해 순위를 명시적으로 매긴 후, 3위 이하의 데이터만 필터링하는 방법입니다.
WITH SUM_ORDERS AS (
-- 상반기와 7월 데이터를 합친 후, 맛별 총 주문량을 계산
SELECT FLAVOR, SUM(TOTAL_ORDER) AS TOTAL
FROM (
SELECT FLAVOR, TOTAL_ORDER FROM FIRST_HALF
UNION ALL
SELECT FLAVOR, TOTAL_ORDER FROM JULY
) COMBINED -- UNION ALL로 합쳐진 괄호 안의 결과물에 'COMBINED'라는 임시 테이블 이름(Alias) 부여
GROUP BY FLAVOR
),
RANKED_ORDERS AS (
-- 맛별 총 주문량을 기준으로 내림차순 순위(RANK) 부여
SELECT FLAVOR,
RANK() OVER (ORDER BY TOTAL DESC) AS rnk
FROM SUM_ORDERS
)
-- 최종적으로 랭크(rnk)가 3 이하인(1~3등) 맛만 조회
SELECT FLAVOR
FROM RANKED_ORDERS
WHERE rnk <= 3;
댓글남기기