본문 바로가기
Data Science/SQL

[SQL/오답] 서브쿼리를 활용한 판매 데이터 사전 집계와 다중 조인 (프로그래머스 Lv4)

by 에르모사 쩐뉴 2026. 2. 15.

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월의 도서 판매 데이터를 기준으로 다음 조건을 만족하는 쿼리를 작성하세요.

  1. 집계 기준: 저자 별, 카테고리 별로 그룹화
  2. 산출 지표: 총 매출액 (TOTAL_SALES = 판매량 × 판매가)
  3. 출력 컬럼: 저자 ID, 저자명, 카테고리, 매출액
  4. 정렬 규칙:
    • 저자 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)를 고려하며 코딩하는가?"

🚩 중심 잡기 

"왜 굳이 서브쿼리를 써야 할까?" 혹은 "한 번에 조인하면 안 될까?"라는 고민이 드실 수 있습니다. 하지만 사용자님이 작성하신 것처럼 판매량을 먼저 집계하고 조인하는 방식은 실무에서 시니어 개발자들이 선호하는 '깔끔하고 빠른' 방식입니다.