438. GROUP BY 다차원 집계 (ROLLUP, CUBE)
⚠️ 이 문서는 "부서별 급여 합계도 구하고, 부서 안에서 직급별 합계도 구하고, 전체 회사 총합계도 한 번에 다 뽑아와!"라는 엑셀의 '피벗 테이블(Pivot Table)' 같은 깐깐한 요구사항을, **단 한 번의 쿼리로 해결해 주는 '다차원 그룹 함수(ROLLUP, CUBE)'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 기존
GROUP BY가 단순한 하나의 그룹 합계만 구해준다면,ROLLUP과CUBE는 개발자가 일일이UNION ALL로 합쳐야 했던 여러 레벨의 '소계(Subtotal)'와 '총계(Grand Total)'를 자동으로 계산해 주는 고급 집계 함수다.- ROLLUP: 인자로 들어온 컬럼의 오른쪽에서부터 하나씩 빼가며 **'계층적인 소계'**를 구한다. (예:
연도별 총합$\rightarrow$연도-월별 소계$\rightarrow$전체 총합)- 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)가 터져버린다. ROLLUP과 CUBE는 "계산은 데이터를 가장 잘 아는 데이터베이스 엔진 내부에서 끝내고, 앱에는 요약된 결과만 가볍게 던져주어라"는 데이터베이스 튜닝의 철학을 가장 잘 보여주는 강력한 함수다.
📌 관련 개념 맵
- 관련 문법:
GROUP BY,GROUPING SETS()(원하는 조합만 골라서 소계 내기) - 보완 함수:
GROUPING()(합계 줄인지 진짜 널인지 구별하는 함수) - 데이터 창고: Data Warehouse, OLAP (321번 문서 - 이런 다차원 분석 쿼리가 주로 도는 곳)
👶 어린이를 위한 3줄 비유 설명
GROUP BY는 우리 반 친구들의 수학 점수를 '분단별'로 합쳐서 평균을 구해주는 엑셀 기능이에요.ROLLUP은 분단별 평균을 구한 다음에, 제일 밑에다가 아주 친절하게 **'우리 반 전체 평균'**까지 한 줄 덤으로 끼워 넣어주는 보너스 기능이죠.CUBE는 분단별 평균, 성별 평균, 안경 쓴 애들 평균 등 내가 할 수 있는 모든 조합의 평균을 싹 다 구해서 보여주는 엄청난 계산기랍니다!