1. 주문량이 많은 아이스크림 조회하기
https://school.programmers.co.kr/learn/courses/30/lessons/133027?language=oracle
방법1) JOIN을 활용한 풀이
SELECT H.FLAVOR
FROM (SELECT
FLAVOR,
SUM(TOTAL_ORDER) AS HALF_ORDER
FROM FIRST_HALF
GROUP BY FLAVOR) H
JOIN (SELECT
FLAVOR,
SUM(TOTAL_ORDER) AS JULY_ORDER
FROM JULY
GROUP BY FLAVOR) J
ON H.FLAVOR = J.FLAVOR
ORDER BY H.HALF_ORDER + J.JULY_ORDER DESC
FETCH FIRST 3 ROWS ONLY;
방법2) UNION ALL을 활용한 풀이
SELECT flavor
FROM (
SELECT flavor, total_order FROM first_half
UNION ALL
SELECT flavor, total_order FROM july
) t
GROUP BY flavor
ORDER BY SUM(total_order) DESC
FETCH FIRST 3 ROWS ONLY;
POINT!
이번 문제에서는 같은 맛이라도 7월에는 여러 출하 번호로 나뉘어 들어올 수 있다고 문제에서 명시했습니다.
그래서 7월 테이블(JULY) 안에서도 같은 FLAVOR가 여러 행으로 존재할 수 있고, 상반기 테이블과 합치면 더더욱 중복 행이 많아집니다.
우리가 원하는 건 맛(FLAVOR)별 전체 주문량 합계이니까, 중복을 제거하면 안 되고 그대로 합쳐야 해요.
👉따라서 UNION을 쓰면 안 되고 UNION ALL을 써야 맛별 주문량이 제대로 합산됩니다.
UNION ALL
개념: 두 결과 집합을 세로로 합치는 연산자
사용 조건 : UNION ALL을 쓰려면 컬럼 개수, 순서, 타입이 일치해야 한다.
UNION / UNION ALL의 조건
- 컬럼 개수가 동일해야 함
- SELECT 절의 컬럼 개수가 같아야 함
- 컬럼 순서가 동일해야 함
- 첫 번째 SELECT의 1번 컬럼 ↔ 두 번째 SELECT의 1번 컬럼
- 두 번째 SELECT의 2번 컬럼 ↔ 첫 번째 SELECT의 2번 컬럼 … 이렇게 매칭됨
- 컬럼 타입이 호환 가능해야 함
- 예: 첫 번째 SELECT에서 숫자, 두 번째 SELECT에서 문자열을 같은 위치에 두면 안 됨
UNION / UNION ALL의 차이
| 구분 | UNION | UNION ALL |
| 중복 처리 | 중복 행을 제거 (DISTINCT) | 중복 행을 그대로 포함 |
| 정렬 여부 | 내부적으로 중복 제거를 위해 정렬/해시 연산 수행 | 정렬 없이 단순히 합침 |
| 속도 | 상대적으로 느림 (중복 제거 작업 추가됨) | 빠름 (단순 합치기) |
| 사용 목적 | “서로 다른 데이터만 보고 싶을 때” | “모든 데이터를 그대로 보고 싶을 때” |
2. 그룹별 조건에 맞는 식당 목록 출력하기
https://school.programmers.co.kr/learn/courses/30/lessons/131124?language=oracle
핵심 : 리뷰를 가장 많이 작성한 회원의 리뷰들을 조회
RANK() OVER (ORDER BY COUNT(REVIEW_ID) DESC)
GROUP BY MEMBER_ID를 하면 이미 회원별 리뷰 개수가 집계된 상태니까, 그 시점에서 RANK()는 전체 회원을 기준으로 순위를 매기면 된다.
풀이)
WITH T AS (SELECT
MEMBER_ID,
COUNT(REVIEW_ID) AS REVIEW_COUNTS,
RANK() OVER (ORDER BY COUNT(REVIEW_ID) DESC) AS RK
FROM REST_REVIEW
GROUP BY MEMBER_ID)
SELECT
M.MEMBER_NAME,
R.REVIEW_TEXT,
TO_CHAR(R.REVIEW_DATE, 'YYYY-MM-DD') AS "REVIEW_DATE"
FROM MEMBER_PROFILE M
JOIN REST_REVIEW R
ON M.MEMBER_ID = R.MEMBER_ID
WHERE M.MEMBER_ID IN (
SELECT MEMBER_ID
FROM T
WHERE RK = 1
)
ORDER BY REVIEW_DATE, REVIEW_TEXT;
POINT
과거에는 MySQL에서 LIMIT 1로 최다 리뷰 회원을 한 명만 선택했는데, 이 방식은 공동 1등이 존재할 때 동점자를 누락시킨다는 한계가 있었습니다.
실제로 데이터를 확인해 보니 최다 리뷰 수가 동일한 회원이 여러 명이었습니다.
그래서 이번에는 회원별 리뷰 수를 집계한 뒤 윈도우 함수 RANK()로 순위를 매겨 RANK = 1인 모든 회원을 대상으로 리뷰를 조회하도록 설계했습니다.
프로그래머스에서는 과거 풀이도 정답 처리되었지만, 요건 충족 관점에서는 이번 접근이 더 정확하다고 판단합니다.
'코딩 테스트 > 02. SQL' 카테고리의 다른 글
| [프로그래머스]Oracle SQL_7(Lv4) (0) | 2025.10.04 |
|---|---|
| [프로그래머스]Oracle SQL_6(Lv4)/UNION ALL과 CONNECT BY (0) | 2025.10.03 |
| [프로그래머스]Oracle SQL_4(Lv4) (0) | 2025.10.02 |
| [프로그래머스]Oracle SQL_3(Lv4) (0) | 2025.09.29 |
| [프로그래머스]Oracle SQL_2(Lv4) (1) | 2025.09.28 |