I know I could easily use UNION ALL
to get the results I want, but I have to generate 5 tables of each containing 15 rows of metrics/KPI.
To simplify, I have data like this:
user | sex | state | race |
---|---|---|---|
usr1 | M | PA | B |
usr2 | F | TX | W |
usr3 | M | TX | B |
usr4 | D | NE | H |
usr5 | F | TX | A |
As a result, I need to format the data like:
Category | Total | Percentage |
---|---|---|
Total | 5 | 100% |
Male | 2 | 40% |
Female | 2 | 40% |
Other/Declined | 1 | 20% |
In State | 3 | 60% |
Out State | 2 | 40% |
Black | 2 | 40% |
White | 1 | 20% |
I know I could write a unioned query such as:
SELECT
'Total' AS Category
, COUNT(ud.user) AS Total
, '100%' AS Percentage
FROM UserData ud
UNION ALL
SELECT
'Male' AS Category
, SUM(CASE WHEN ud.sex = 'M' THEN 1 END) AS Total
, (SUM(CASE WHEN ud.sex = 'M' THEN 1 END) / COUNT(ud.user)) * 100 AS Percentage
FROM UserData ud
UNION ALL
...
FROM ...
UNION ...
If unions really are the only/best/most sensible way, so be it. I feel like there should be a way to do this with a relatively singular query rather than blocks of 15 unioned queries. Is there a way to do this with PIVOT/UNPIVOT or something else, or am I doomed to unions?
It seems the solution here is just a simple UNPIVOT and I was struggling to wrap my head around/conceptualize it. I think needing the percentage was making this seem more complicated than it needed to be.
None of these answers really got me to the result I needed, however this is what I ended up using which generates the result table in my question perfectly. I'll wait a little bit to see if a better solution is posted before accepting this answer.
WITH upvt AS (
SELECT *
FROM (
SELECT
COUNT(ud.userid) AS Total
, SUM(CASE WHEN ud.sex = 'M' THEN 1 END) AS Male
, SUM(CASE WHEN ud.sex = 'F' THEN 1 END) AS Female
, SUM(CASE WHEN ud.sex = 'D' THEN 1 END) AS Declined
, SUM(CASE WHEN ud.state = 'tx' THEN 1 END) AS [In State]
, SUM(CASE WHEN ud.state <> 'tx' THEN 1 END) AS [Out State]
, SUM(CASE WHEN ud.race = 'B' THEN 1 END) AS Black
, SUM(CASE WHEN ud.race = 'W' THEN 1 END) AS White
, SUM(CASE WHEN ud.race = 'H' THEN 1 END) AS Hispanic
, SUM(CASE WHEN ud.race = 'A' THEN 1 END) AS Asian
FROM UserData ud
) p
UNPIVOT (
Totals FOR Category IN (Total, Male, Female, Declined, [In State], [Out State], Black, White, Hispanic, Asian)
) AS up
)
SELECT
u.Category
, u.Totals
, (CAST(u.Totals AS FLOAT) / CAST(u2.Totals AS FLOAT)) * 100 AS Percentage
FROM upvt u
CROSS JOIN (
SELECT * FROM upvt WHERE Category = 'Total'
) u2