1. Problem
2022년 1월 도서 판매 데이터를 기준으로 저자별, 카테고리별 총 매출액(판매량 × 판매가)을 산출해야 한다. 서로 다른 성격의 세 테이블(BOOK, AUTHOR, BOOK_SALES)을 결합해야 하며, 저자라는 큰 단위 안에 카테고리라는 세부 단위를 중첩하여 그룹화하는 정밀한 집계 역량이 요구된다.
2. Solution
가장 큰 부하가 예상되는 BOOK_SALES 테이블을 먼저 처리한 뒤, 나머지 마스터 테이블들과 조인하는 '선(先) 필터링 후(後) 조인' 전략을 사용한다.
- 서브쿼리 활용 (SUB): 수만 건에 달할 수 있는 판매 로그를 조인하기 전에 미리 월별 합계로 축소시켜 조인 연산의 비용을 획기적으로 줄였다.
- 다차원 그룹화: AUTHOR_ID와 CATEGORY를 함께 묶어 저자별 포트폴리오(어떤 분야의 책을 얼마나 팔았는지)를 한눈에 보여준다.
3. Takeaway (실무 리포트의 성능과 확장성)
효율적인 쿼리 설계를 통해 데이터 분석가가 지향해야 할 객관적인 설계 원칙을 정리한다.
- 데이터 다이어트의 중요성: 모든 테이블을 한꺼번에 조인한 뒤 필터링하는 것보다, 필요한 부분집합을 먼저 추출한 뒤 조인하는 것이 대규모 데이터베이스 환경에서는 훨씬 객관적인 성능 우위를 점한다.
- 비즈니스 지표의 입체적 분석: 단순히 저자별 매출만 보는 것이 아니라 카테고리를 추가함으로써, "특정 저자가 어떤 장르에서 강세를 보이는가?"와 같은 심층적인 비즈니스 인사이트 도출이 가능해진다.
- 데이터 무결성 유지: 가격(PRICE)은 BOOK 테이블에, 판매량(SALES)은 BOOK_SALES에 있는 파편화된 구조에서도 정확한 곱셈 연산과 합산을 통해 '총 매출액'이라는 새로운 가치를 창출해냈다.
https://school.programmers.co.kr/learn/courses/30/lessons/144856
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
1. 데이터 테이블 구조
📘 도서 정보 (BOOK)
| Column name | Type | Nullable | Description |
| BOOK_ID | INTEGER | FALSE | 도서 ID |
| CATEGORY | VARCHAR(N) | FALSE | 카테고리 (경제, 인문, 소설 등) |
| AUTHOR_ID | INTEGER | FALSE | 저자 ID |
| PRICE | INTEGER | FALSE | 판매가 (원) |
| PUBLISHED_DATE | DATE | FALSE | 출판일 |
👤 저자 정보 (AUTHOR)
| Column name | Type | Nullable | Description |
| AUTHOR_ID | INTEGER | FALSE | 저자 ID |
| AUTHOR_NAME | VARCHAR(N) | FALSE | 저자명 |
📈 도서 판매 정보 (BOOK_SALES)
| Column name | Type | Nullable | Description |
| BOOK_ID | INTEGER | FALSE | 도서 ID |
| SALES_DATE | DATE | FALSE | 판매일 |
| SALES | INTEGER | FALSE | 판매량 |
2. 문제 요구사항
2022년 1월의 도서 판매 데이터를 기준으로 다음 조건을 만족하는 쿼리를 작성하세요.
- 집계 기준: 저자 별, 카테고리 별로 그룹화
- 산출 지표: 총 매출액 (TOTAL_SALES = 판매량 × 판매가)
- 출력 컬럼: 저자 ID, 저자명, 카테고리, 매출액
- 정렬 규칙:
- 저자 ID 기준 오름차순 (ASC)
- 저자 ID가 같다면 카테고리 기준 내림차순 (DESC)
3. 문제 풀이 접근법 (Core Logic)
① 데이터 필터링과 사전 집계 (서브쿼리 활용)
BOOK_SALES 테이블은 판매 로그가 쌓이는 곳이므로 데이터양이 매우 많을 수 있습니다. 따라서 메인 쿼리에서 조인하기 전에 2022년 1월 데이터만 미리 합산하는 서브쿼리를 사용하는 것이 성능 최적화의 핵심입니다.
② 다중 테이블 조인 (Join)
- BOOK (도서 정보) ↔ AUTHOR (저자명 확인을 위해 조인)
- BOOK (도서 정보) ↔ BOOK_SALES (판매량 확인을 위해 조인)
③ 최종 그룹화 및 정렬
결과적으로 한 명의 저자가 여러 카테고리의 책을 쓸 수 있으므로, AUTHOR_ID와 CATEGORY를 함께 묶어(GROUP BY) 최종 매출액을 산출합니다.
1. 정답 쿼리
SELECT B.AUTHOR_ID, A.AUTHOR_NAME, B.CATEGORY, SUM(B.PRICE*SUB.SALES) AS TOTAL_SALES
FROM BOOK B
JOIN AUTHOR A ON B.AUTHOR_ID = A.AUTHOR_ID
JOIN (SELECT BOOK_ID, SUM(SALES) AS SALES
FROM BOOK_SALES
WHERE SALES_DATE LIKE '2022-01%'
GROUP BY BOOK_ID
) SUB ON B.BOOK_ID = SUB.BOOK_ID
GROUP BY B.AUTHOR_ID, A.AUTHOR_NAME, B.CATEGORY
ORDER BY B.AUTHOR_ID ASC, B.CATEGORY DESC;
1. 문제 풀이 방향: "데이터를 먼저 줄이고 합쳐라"
사용자님은 BOOK_SALES 테이블에서 2022년 1월 데이터만 미리 뽑아 SUM을 한 뒤(SUB 서브쿼리), 이를 메인 테이블과 조인하셨습니다.
- 장점: 대량의 판매 로그를 미리 BOOK_ID별로 합산했기 때문에 조인해야 할 행(Row)의 수가 급격히 줄어듭니다. 이는 대규모 데이터 환경에서 쿼리 성능을 최적화하는 아주 좋은 습관입니다.
2. 핵심 사항 (Key Points)
- 다중 조인 (Triple Join): 도서(BOOK), 저자(AUTHOR), 판매(SALES) 세 테이블의 관계를 정확히 이해하고 공통 컬럼(AUTHOR_ID, BOOK_ID)으로 연결하는 능력이 필요합니다.
- 집계 로직: 매출액(TOTAL_SALES)은 단일 상품의 가격이 아니라, 판매량(SALES) * 판매가(PRICE)의 총합(SUM)임을 정확히 구현해야 합니다.
- 날짜 필터링: LIKE '2022-01%' 또는 DATE_FORMAT 등을 활용해 특정 연월의 데이터만 정확히 골라내는 것이 관건입니다.
- 다중 그룹화: 저자별로 끝나는 게 아니라 그 안에서 다시 카테고리별로 나눠야 하므로 GROUP BY에 두 컬럼이 모두 들어가야 합니다.
🎯 기업 쿼리테스트 출제자의 의도
이 문제는 실무에서 가장 빈번하게 발생하는 '월간 실적 리포트' 추출 능력을 검증합니다.
① 복합적인 그룹화(Aggregation) 능력
단순히 전체 매출을 구하는 것이 아니라, **저자(Entity 1)**와 **카테고리(Entity 2)**라는 두 가지 차원(Dimension)으로 데이터를 쪼개서 볼 수 있는지 확인합니다.
- 의도: "복잡한 비즈니스 지표를 다각도로 분석할 수 있는가?"
② 데이터 가공 및 연산 처리
BOOK 테이블에는 가격이 있고, BOOK_SALES 테이블에는 수량이 있습니다. 서로 다른 테이블의 값을 곱해서 합산하는 과정을 통해 데이터 간의 관계를 수식으로 풀어낼 수 있는지 봅니다.
- 의도: "서로 파편화된 데이터를 결합해 의미 있는 정보(매출액)를 창출할 수 있는가?"
③ 효율적인 쿼리 구조 설계
판매 데이터는 보통 행 수가 가장 많습니다. 이를 무작정 조인하지 않고, 사용자님처럼 서브쿼리나 효율적인 그룹화를 통해 시스템 부하를 줄이려는 고민을 하는지 평가합니다.
- 의도: "성능 최적화(Performance Tuning)를 고려하며 코딩하는가?"
🚩 중심 잡기
"왜 굳이 서브쿼리를 써야 할까?" 혹은 "한 번에 조인하면 안 될까?"라는 고민이 드실 수 있습니다. 하지만 사용자님이 작성하신 것처럼 판매량을 먼저 집계하고 조인하는 방식은 실무에서 시니어 개발자들이 선호하는 '깔끔하고 빠른' 방식입니다.
'Data Science > SQL' 카테고리의 다른 글
| [SQL] AARRR이란?, 쿼리테스트 출제 유형, 관련 함수 (0) | 2026.02.15 |
|---|---|
| [SQL] 코호트 분석이란?, 쿼리테스트 출제 유형, 관련 함수 (0) | 2026.02.15 |
| [SQL] 비트연산&, 기간중복, 서브쿼리 Alias 규칙, EXISTS, HAVING (0) | 2026.02.15 |
| [SQL/오답] 기간별 할인 로직 구현; WITH 절과 LEFT JOIN의 조화 (프로그래머스 Lv4) (1) | 2026.02.15 |
| [SQL/오답] 기간 중복(Overlap)와 다중 테이블 조인을 활용한 대여 가능 차량 조회 (프로그래머스 Lv4) (0) | 2026.02.15 |