438. GROUP BY 다차원 집계 (ROLLUP, CUBE)

⚠️ 이 문서는 "부서별 급여 합계도 구하고, 부서 안에서 직급별 합계도 구하고, 전체 회사 총합계도 한 번에 다 뽑아와!"라는 엑셀의 '피벗 테이블(Pivot Table)' 같은 깐깐한 요구사항을, **단 한 번의 쿼리로 해결해 주는 '다차원 그룹 함수(ROLLUP, CUBE)'**를 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 기존 GROUP BY가 단순한 하나의 그룹 합계만 구해준다면, ROLLUPCUBE는 개발자가 일일이 UNION ALL로 합쳐야 했던 여러 레벨의 '소계(Subtotal)'와 '총계(Grand Total)'를 자동으로 계산해 주는 고급 집계 함수다.
  2. ROLLUP: 인자로 들어온 컬럼의 오른쪽에서부터 하나씩 빼가며 **'계층적인 소계'**를 구한다. (예: 연도별 총합 $\rightarrow$ 연도-월별 소계 $\rightarrow$ 전체 총합)
  3. CUBE: 인자로 들어온 컬럼으로 만들 수 있는 **'모든 경우의 수(조합)'**에 대한 소계를 다 구한다. (가장 무겁고 데이터가 많이 나옴)

Ⅰ. 개요: 지옥의 UNION ALL (Context & Necessity)

"영업팀 전체 매출, 개발팀 전체 매출, 그리고 회사 전체 총매출을 한 표에 다 보여줘."

이걸 순수 SQL로 짜려면 끔찍한 코드가 나온다.

SELECT 부서, SUM(매출) FROM 직원 GROUP BY 부서  -- 부서별 합계
UNION ALL
SELECT '총계', SUM(매출) FROM 직원;              -- 전체 합계

조건이 3개(지역, 부서, 직급)로 늘어나면 UNION ALL을 5번은 써야 한다. 코드는 100줄이 넘어가고, DB는 똑같은 테이블을 5번이나 풀 스캔(Full Scan)해야 한다. (서버 터짐)

이때 **ROLLUP**을 쓰면 단 한 줄로 끝난다.

SELECT 지역, 부서, SUM(매출) FROM 직원 
GROUP BY ROLLUP(지역, 부서);

DB는 테이블을 딱 1번만 스캔해서 지역+부서 소계, 지역별 소계, 전체 총계를 한방에 뱉어낸다.

📢 섹션 요약 비유: UNION ALL이 영수증에 물건값을 일일이 적고 계산기로 **'직접 더해서 밑줄을 긋는 노가다'**라면, ROLLUP은 마트 포스기(POS)에서 영수증을 뽑을 때 **'자동으로 중간 합계와 최종 합계가 찌지직 찍혀 나오는 마법'**과 같습니다.


Ⅱ. ROLLUP vs CUBE 완벽 비교 ★

시험에서 "다음 중 결과 행의 개수가 가장 많은 것은?"이라는 문제로 매번 출제된다. 기준 컬럼이 A, B 두 개일 때를 비교해 보자.

1. 일반 GROUP BY (A, B)

  • 계산하는 그룹: (A, B)
  • A와 B가 완벽히 일치하는 그룹의 합계 딱 하나만 구하고 끝난다.

2. ROLLUP (A, B) - 계층적 소계

  • 계산하는 그룹: (A, B), (A), ()
  • 오른쪽 컬럼(B)부터 하나씩 떼어내면서 합계를 구한다.
  • A(연도) 안에 B(월)가 속해있는 **'계층적인 데이터'**에서 주로 쓴다. (예: 2026년 4월 매출 $\rightarrow$ 2026년 전체 매출 $\rightarrow$ 회사 전체 매출)

3. CUBE (A, B) - 모든 경우의 수 (다차원)

  • 계산하는 그룹: (A, B), (A), (B), ()
  • A와 B로 만들 수 있는 수학적인 모든 조합($2^n$ 개)에 대한 소계를 다 구한다.
  • A와 B가 계층적이지 않고 대등한 조건(예: 성별과 지역)일 때, 엑셀의 다차원 큐브(OLAP) 분석을 위해 쓴다.

Ⅲ. 실무 팁: 텅 빈 공간(NULL)을 채우는 GROUPING()

ROLLUP이나 CUBE로 총계를 구하면, "이 줄은 전체 합계 줄이야!"라는 걸 표시하기 위해 남는 컬럼 칸을 NULL로 채워서 반환해 버린다.

  • 결과 예시: [NULL, NULL, 100억] (이게 회사 총매출임)

화면에 널(Null)을 그대로 보여주면 사용자가 싫어한다. 그래서 GROUPING() 함수를 같이 써서 예쁘게 화장을 해준다.

SELECT 
    CASE WHEN GROUPING(지역) = 1 THEN '전국 총계' ELSE 지역 END AS 지역,
    SUM(매출) 
FROM 직원 
GROUP BY ROLLUP(지역);

이렇게 치면 꼴 보기 싫은 NULL 대신 화면에 **'전국 총계'**라는 글씨가 아주 예쁘게 찍혀서 나온다.

┌──────────────────────────────────────────────────────────────┐
│           GROUP BY ROLLUP (지역, 성별) 결과 시각화               │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 지역   │ 성별 │ 매출                                           │
│ ──────┼──────┼────────                                       │
│ 서울   │ 남   │ 100        ◀── (일반 GROUP BY 레벨)            │
│ 서울   │ 여   │ 200                                          │
│ 서울   │ NULL │ 300 🌟     ◀── (서울 지역 '소계' - ROLLUP 생성) │
│ ────┼──────┼────────                                       │
│ 부산   │ 남   │ 50                                           │
│ 부산   │ NULL │ 50  🌟     ◀── (부산 지역 '소계' - ROLLUP 생성) │
│ ────┼──────┼────────                                       │
│ NULL   │ NULL │ 350 🔥     ◀── (전국 '총계' - ROLLUP 생성)     │
│                                                              │
│ ★ 특징: 쿼리 한 방에 디테일한 데이터부터 거대한 총합까지 모두 쏟아져 나온다!│
└──────────────────────────────────────────────────────────────┘

Ⅳ. 결론

"복잡한 통계를 위해 서버로 데이터를 퍼 나르지 마라." 백엔드 개발자들은 통계 화면을 짤 때 습관적으로 SELECT *로 원본 데이터를 다 가져온 뒤 자바(Java)의 Stream API를 써서 합계를 구하려 한다. 데이터가 100만 건이면 자바 메모리(Heap)가 터져버린다. ROLLUPCUBE는 "계산은 데이터를 가장 잘 아는 데이터베이스 엔진 내부에서 끝내고, 앱에는 요약된 결과만 가볍게 던져주어라"는 데이터베이스 튜닝의 철학을 가장 잘 보여주는 강력한 함수다.


📌 관련 개념 맵

  • 관련 문법: GROUP BY, GROUPING SETS() (원하는 조합만 골라서 소계 내기)
  • 보완 함수: GROUPING() (합계 줄인지 진짜 널인지 구별하는 함수)
  • 데이터 창고: Data Warehouse, OLAP (321번 문서 - 이런 다차원 분석 쿼리가 주로 도는 곳)

👶 어린이를 위한 3줄 비유 설명

  1. GROUP BY는 우리 반 친구들의 수학 점수를 '분단별'로 합쳐서 평균을 구해주는 엑셀 기능이에요.
  2. ROLLUP은 분단별 평균을 구한 다음에, 제일 밑에다가 아주 친절하게 **'우리 반 전체 평균'**까지 한 줄 덤으로 끼워 넣어주는 보너스 기능이죠.
  3. CUBE는 분단별 평균, 성별 평균, 안경 쓴 애들 평균 등 내가 할 수 있는 모든 조합의 평균을 싹 다 구해서 보여주는 엄청난 계산기랍니다!