DB/PostgreSQL
[PostgreSQL] ROLLUP을 사용해 소계 구하기
불곰1
2021. 2. 28. 17:15
먼저 아래와 같은 데이터가 있다고 가정합니다.
dt | order_id | user_id | item_id | price | category | sub_category |
2017-01-01 | 1 | 1 | 1 | 10000 | men | jacket |
2017-01-01 | 1 | 1 | 2 | 5000 | food | fish |
2017-01-01 | 1 | 1 | 3 | 2500 | book | business |
2017-01-01 | 2 | 2 | 1 | 10000 | men | jacket |
2017-01-01 | 2 | 2 | 5 | 50000 | women | bag |
2017-01-01 | 3 | 2 | 2 | 5000 | food | fish |
2017-01-01 | 4 | 3 | 1 | 10000 | men | jacket |
2017-01-01 | 5 | 4 | 4 | 40000 | cd | classic |
이러한 데이터에서 카테고리별 총 매출과 소계를 계산하고자 합니다. 소계란 전체가 아닌 부분의 합을 말합니다. 즉, 아래 표와 같이 모든 카테고리의 매출(총계)과 sub_category 별 매출(소계), category별 매출(소계)을 집계하고자 하는 것입니다.
category | sub_category | 매출 |
all | all | ~~~ |
men | all | ~~~ |
men | jacket | ~~~ |
women | all | ~~~ |
먼저 ROLLUP을 사용하지 않고 이 소계와 총계를 한번에 출력하고자 한다면, 각 카테고리 별로 집계한 결과를 같은 컬럼이 되게 변환한 다음 UNION ALL로 1개의 테이블화 시키면 됩니다.
WITH
sub_category_amount AS (
SELECT
category,
sub_category,
SUM(price) AS amount
FROM purchase_log
GROUP BY category, sub_category
)
, category_amount AS (
SELECT
category,
'all' AS sub_category,
SUM(price) AS amount
FROM purchase_log
GROUP BY category
)
, total_amount AS (
SELECT
'all' AS category,
'all' AS sub_category,
SUM(price) AS amount
FROM purchase_log
)
SELECT * FROM sub_category_amount
UNION ALL
SELECT * FROM category_amount
UNION ALL
SELECT * FROM total_amount;
이와 같이 WITH문과 UNION ALL문을 사용해 계산할 순 있지만 UNION ALL의 계산 비용은 비싼 편이라 성능이 좋지 않습니다. ROLLUP 구문을 사용하면 이러한 문제를 해결할 수 있습니다.
SELECT
COALESCE(category, 'all') AS category,
COALESCE(sub_category, 'all') AS sub_category,
SUM(price) AS amount
FROM purchase_log
GROUP BY ROLLUP(category, sub_category);
ROLLUP
ROLLUP문을 사용할 때, 주의해야 할 점은 지정한 순서대로 소계하기 때문에 순서가 변경되면 결과가 달라질 수 있습니다. 위 ROLLUP을 사용한 쿼리의 결과는 아래와 같이 나올 수 있습니다.
category | sub_category | amount |
men | jacket | 30000 |
men | all | 30000 |
women | bag | 50000 |
women | all | 50000 |
all | all | 132500 |
ROLLUP은 아래와 같은 형태로 사용하면 됩니다.
SELECT C1, C2, C3, 집계함수(C4)
FROM TABLE_NAME
GROUP BY ROLLUP (C1, C2, C3);
-- 특정 컬럼 제외 가능
SELECT C1, C2, C3, 집계함수(C4)
FROM TABLE_NAME
GROUP BY C1 ROLLUP (C2, C3);