http://sqlfiddle.com/#!4/ce4143/31
Вы можете сделать это следующим образом
WITH INTER_RESULT AS
(
SELECT *
FROM (SELECT Possible_Values.Choices_Group,
Possible_Values.Age_Group,
COALESCE(TEST_DATA.east,0) AS east,
COALESCE(TEST_DATA.west,0) AS west,
COALESCE(TEST_DATA.middle,0) AS middle,
COALESCE(TEST_DATA.east,0) +
COALESCE(TEST_DATA.west,0) +
COALESCE(TEST_DATA.middle,0) AS region_total
FROM (SELECT Choices_Group,
Age_Group
FROM (SELECT DISTINCT Choices_Group AS Choices_Group
FROM TEST_DATA
WHERE age_group IS NOT NULL
) CG,
(SELECT DISTINCT AGE_GROUP AS AGE_GROUP
FROM TEST_DATA
WHERE age_group IS NOT NULL
) TD
) Possible_Values
LEFT
JOIN TEST_DATA
ON Possible_Values.Choices_Group = TEST_DATA.Choices_Group
AND Possible_Values.Age_Group = TEST_DATA.Age_Group
)
)
SELECT *
FROM (
SELECT *
FROM INTER_RESULT
UNION
SELECT Choices_Group,
MAX('Age Total') AS AGE_GROUP,
SUM(east),
SUM(west),
SUM(middle),
SUM(region_total)
FROM INTER_RESULT
GROUP
BY choices_group
) TMP
ORDER
BY Choices_Group,
CASE WHEN Age_Group = 'Age Total' THEN 'Z'
ELSE Age_Group
END;
... или, вот где функция ROLLUP может пригодиться.
WITH INTER_RESULT AS
(
SELECT *
FROM (SELECT Possible_Values.Choices_Group,
Possible_Values.Age_Group,
COALESCE(TEST_DATA.east,0) AS east,
COALESCE(TEST_DATA.west,0) AS west,
COALESCE(TEST_DATA.middle,0) AS middle,
COALESCE(TEST_DATA.east,0) +
COALESCE(TEST_DATA.west,0) +
COALESCE(TEST_DATA.middle,0) AS region_total
FROM (SELECT Choices_Group,
Age_Group
FROM (SELECT DISTINCT Choices_Group AS Choices_Group
FROM TEST_DATA
WHERE age_group IS NOT NULL
) CG,
(SELECT DISTINCT AGE_GROUP AS AGE_GROUP
FROM TEST_DATA
WHERE age_group IS NOT NULL
) TD
) Possible_Values
LEFT
JOIN TEST_DATA
ON Possible_Values.Choices_Group = TEST_DATA.Choices_Group
AND Possible_Values.Age_Group = TEST_DATA.Age_Group
)
)
SELECT Choices_Group,
COALESCE(Age_Group,'Age Total') AS Age_Group,
East,
West,
Middle,
Region_Total
FROM (SELECT Choices_Group,
Age_Group,
SUM(East) AS East,
SUM(West) AS West,
SUM(Middle) AS Middle,
SUM(region_total) AS region_total
FROM INTER_RESULT
GROUP
BY ROLLUP(Choices_Group,
Age_Group)
) TMP
WHERE Choices_Group IS NOT NULL;
Редактировать: для процентов.Не очень красиво, но это сработает.
WITH INTER_RESULT AS
(
SELECT *
FROM (SELECT Possible_Values.Choices_Group,
Possible_Values.Age_Group,
COALESCE(TEST_DATA.east,0) AS east,
COALESCE(TEST_DATA.west,0) AS west,
COALESCE(TEST_DATA.middle,0) AS middle,
COALESCE(TEST_DATA.east,0) +
COALESCE(TEST_DATA.west,0) +
COALESCE(TEST_DATA.middle,0) AS region_total
FROM (SELECT Choices_Group,
Age_Group
FROM (SELECT DISTINCT Choices_Group AS Choices_Group
FROM TEST_DATA
WHERE age_group IS NOT NULL
) CG,
(SELECT DISTINCT AGE_GROUP AS AGE_GROUP
FROM TEST_DATA
WHERE age_group IS NOT NULL
) TD
) Possible_Values
LEFT
JOIN TEST_DATA
ON Possible_Values.Choices_Group = TEST_DATA.Choices_Group
AND Possible_Values.Age_Group = TEST_DATA.Age_Group
)
)
SELECT *
FROM (
SELECT *
FROM INTER_RESULT
UNION
SELECT Choices_Group,
MAX('Percentage of Total') AS AGE_GROUP,
SUM(east)/(SELECT SUM(east) FROM INTER_RESULT),
SUM(west)/(SELECT SUM(west) FROM INTER_RESULT),
SUM(middle)/(SELECT SUM(middle) FROM INTER_RESULT),
SUM(region_total)/(SELECT SUM(region_total) FROM INTER_RESULT)
FROM INTER_RESULT
GROUP
BY choices_group
) TMP
ORDER
BY Choices_Group,
CASE WHEN Age_Group = 'Percentage of Total' THEN 'Z'
ELSE Age_Group
END