ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [PostgreSQL] ROLLUP을 사용해 소계 구하기
    DB/PostgreSQL 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);

    댓글