W
Whenever you need to multiple aggregations you should use GROUPING SETS or CUBE or ROLLUP. I like grouping sets, because they are more clear/readable and because often I don't need all aggregations/combinations.
WITH t AS (
SELECT 'A' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 2 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 40 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 3 AS day_, 50 AS val FROM DUAL
)
SELECT
t.group_name,
t.day_,
SUM(t.val) AS sum_val,
--
DECODE(GROUPING_ID(t.group_name, t.day_), 1, 1) AS g1,
DECODE(GROUPING_ID(t.group_name), 1, 1) AS g2,
DECODE(GROUPING_ID(t.day_), 1, 1) AS g3
FROM t
GROUP BY GROUPING SETS (
(t.group_name, t.day_), -- g1
(t.group_name), -- g2
(t.day_), -- g3
()
)
ORDER BY 1, 2 NULLS LAST;
You can achieve same result with CUBE.
WITH t AS (
SELECT 'A' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 2 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 40 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 3 AS day_, 50 AS val FROM DUAL
)
SELECT
t.group_name,
t.day_,
SUM(t.val) AS sum_val,
--
DECODE(GROUPING_ID(t.group_name, t.day_), 1, 1) AS g1,
DECODE(GROUPING_ID(t.group_name), 1, 1) AS g2,
DECODE(GROUPING_ID(t.day_), 1, 1) AS g3
FROM t
GROUP BY CUBE (t.group_name, t.day_)
ORDER BY 1, 2 NULLS LAST;
You can even reduce CUBE sets.
WITH t AS (
SELECT 'A' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 2 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 40 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 3 AS day_, 50 AS val FROM DUAL
)
SELECT
t.group_name,
t.day_,
SUM(t.val) AS sum_val,
--
DECODE(GROUPING_ID(t.group_name, t.day_), 1, 1) AS g1,
DECODE(GROUPING_ID(t.group_name), 1, 1) AS g2,
DECODE(GROUPING_ID(t.day_), 1, 1) AS g3
FROM t
GROUP BY t.group_name, CUBE (t.day_) -- reduce sets
ORDER BY 1, 2 NULLS LAST;
And you should explore ROLLUP too.
WITH t AS (
SELECT 'A' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'A' AS group_name, 2 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 2 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'B' AS group_name, 3 AS day_, 40 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 10 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 1 AS day_, 20 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 2 AS day_, 30 AS val FROM DUAL UNION ALL
SELECT 'C' AS group_name, 3 AS day_, 50 AS val FROM DUAL
)
SELECT
t.group_name,
t.day_,
SUM(t.val) AS sum_val,
--
DECODE(GROUPING_ID(t.group_name, t.day_), 1, 1) AS g1,
DECODE(GROUPING_ID(t.group_name), 1, 1) AS g2,
DECODE(GROUPING_ID(t.day_), 1, 1) AS g3
FROM t
GROUP BY ROLLUP(t.group_name, t.day_)
ORDER BY 1, 2 NULLS LAST;
Comments
Post a Comment