코드 10-1
WITH sub_category_amount AS (
-- 소 카테고리 매출 집계
SELECT category
, sub_category
, SUM(price) AS amount
FROM purchase_detail_log
GROUP BY category, sub_category
)
, category_amount AS (
-- 대 카테고리 매출 집계
SELECT category
, 'all' AS sub_category
, SUM(price) AS amount
FROM purchase_detail_log
GROUP BY category
)
, total_amount AS (
-- 전체 매출 집계
SELECT 'all' AS category
, 'all' AS sub_category
, SUM(price) AS amount
FROM purchase_detail_log
)
SELECT category, sub_category, amount
FROM sub_category_amount
UNION ALL
SELECT category, sub_category, amount
FROM category_amount
UNION ALL
SELECT category, sub_category, amount
FROM total_amount
그런데 UNION ALL을 사용한 결합방법은 성능이 좋지 않다.
ROLLUP을 사용해 쉽고 성능 좋은 쿼리 만들 수 있다.
코드 10-2
SELECT COALESCE(category, 'all') AS category
, COALESCE(sub_category, 'all') AS sub_category
, SUM(price) AS amount
FROM purchase_detail_log
GROUP BY ROLLUP(category, sub_category)
| category | sub_category | amount |
|---|---|---|
| all | all | 861100 |
| ladys_fashion | bag | 127900 |
| food | fish | 32000 |
| food | meats | 48700 |
| dvd | documentary | 32800 |
| mens_fashion | jacket | 116300 |
| book | business | 53500 |
| outdoor | camp | 28600 |
| game | accessories | 26000 |
| ladys_fashion | jacket | 369500 |
| cd | classic | 25800 |
| game | all | 26000 |
| book | all | 53500 |
| ladys_fashion | all | 497400 |
| outdoor | all | 28600 |
| mens_fashion | all | 116300 |
| cd | all | 25800 |
| dvd | all | 32800 |
| food | all | 80700 |
ROLLUP : GROUP BY 절에 사용되는 집계 함수 (링크)
COALESCE : null이 아닌 첫 번째 인수를 반환 (링크)
코드 10-3
WITH monthly_sales AS (
SELECT category
-- 항목별 매출 계산
, SUM(price) AS amount
FROM purchase_detail_log
-- 대상 1개월 동안의 로그를 조건으로 걸기
-- WHERE dt BETWEEN '2015-12-01' AND '2015-12-31'
GROUP BY category
)
, sales_composition_ratio AS (
SELECT category
, amount
-- 구성비
, 100.0 * amount / SUM(amount) OVER() AS composition_ratio
-- 구성비 누계
, 100.0 * SUM(amount) OVER(ORDER BY amount DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
/ SUM(amount) OVER() AS cumulative_ratio
FROM monthly_sales
)
SELECT *
-- 구성비누계 범위에 따라 순위 붙이기
, CASE
WHEN cumulative_ratio BETWEEN 0 AND 70 THEN 'A'
WHEN cumulative_ratio BETWEEN 70 AND 90 THEN 'B'
WHEN cumulative_ratio BETWEEN 90 AND 100 THEN 'C'
END AS abc_rank
FROM sales_composition_ratio
ORDER BY amount DESC
| category | amount | composition_ratio | cumulative_ratio | abc_rank |
|---|---|---|---|---|
| ladys_fashion | 994800 | 57.7633259783997213 | 57.7633259783997213 | A |
| mens_fashion | 232600 | 13.5059807223319011 | 71.2693067007316223 | B |
| food | 161400 | 9.3717338288235977 | 80.6410405295552201 | B |
| book | 107000 | 6.2129833933341075 | 86.8540239228893276 | B |
| dvd | 65600 | 3.8090814075020323 | 90.6631053303913599 | C |
| outdoor | 57200 | 3.3213331784926257 | 93.9844385088839856 | C |
| game | 52000 | 3.0193937986296597 | 97.0038323075136453 | C |
| cd | 51600 | 2.9961676924863547 | 100.0000000000000000 | C |