I have table in SQL Server called df found here:
-- Parameters
DECLARE @Year INT = 2020; --, @Country varchar(50)= 'Brazil';
WITH ModeData AS (
SELECT country,
a.Mode
FROM df
CROSS APPLY (
SELECT TOP 1 Mode, COUNT(*) AS cnt
FROM (VALUES (val1), (val2), (val3)) AS t(Mode)
GROUP BY Mode
ORDER BY COUNT(*) DESC
) a
where year=@year --and country=@country
)
-- Calculate proportions and map modes to labels
, Proportions AS (
SELECT country,
CASE
WHEN Mode = 1 THEN 'Very Dissatisfied'
WHEN Mode = 2 THEN 'Dissatisfied'
WHEN Mode = 3 THEN 'Neutral'
WHEN Mode = 4 THEN 'Satisfied'
WHEN Mode = 5 THEN 'Very Satisfied'
END AS SatisfactionLevel,
COUNT(*) * 1.0 / SUM(COUNT(*)) OVER (PARTITION BY country) AS Proportion
FROM ModeData
GROUP BY country, Mode
)
-- Pivot the results to get each satisfaction level as a column
SELECT country,
[Very Dissatisfied],
[Dissatisfied],
[Neutral],
[Satisfied],
[Very Satisfied]
FROM Proportions
PIVOT (
MAX(Proportion)
FOR SatisfactionLevel IN ([Very Dissatisfied], [Dissatisfied], [Neutral], [Satisfied], [Very Satisfied])
) AS p
ORDER BY country;
The resulted table is :
Country | Very Dissatisfied | Dissatisfied | Neutral | Satisfied | Very Satisfied |
---|---|---|---|---|---|
Brazil | 0.285714285714 | 0.142857142857 | 0.142857142857 | 0.142857142857 | 0.285714285714 |
Canada | 0.111111111111 | 0.111111111111 | 0.333333333333 | 0.222222222222 | 0.222222222222 |
France | 0.250000000000 | 0.125000000000 | 0.250000000000 | 0.250000000000 | 0.125000000000 |
Italy | 0.166666666666 | 0.166666666666 | 0.166666666666 | 0.166666666666 | 0.333333333333 |
USA | 0.222222222222 | 0.111111111111 | 0.111111111111 | 0.333333333333 | 0.222222222222 |
I want to calculate the count of each country.How many rows has each country in the table df and add this count as an extra column in the resulted table. Ideally and based on the toy example data the result I want to look like:
Country | Very Dissatisfied | Dissatisfied | Neutral | Satisfied | Very Satisfied | Count |
---|---|---|---|---|---|---|
Brazil | 0.285714285714 | 0.142857142857 | 0.142857142857 | 0.142857142857 | 0.285714285714 | 7 |
Canada | 0.111111111111 | 0.111111111111 | 0.333333333333 | 0.222222222222 | 0.222222222222 | 9 |
France | 0.250000000000 | 0.125000000000 | 0.250000000000 | 0.250000000000 | 0.125000000000 | 8 |
Italy | 0.166666666666 | 0.166666666666 | 0.166666666666 | 0.166666666666 | 0.333333333333 | 6 |
USA | 0.222222222222 | 0.111111111111 | 0.111111111111 | 0.333333333333 | 0.222222222222 | 9 |
You are way over-complicating it. Instead of calculating each SatisfactionLevel
as a separate group, and then having to pivot it back, just use conditional aggregation.
-- Parameters
DECLARE @Year INT = 2020; --, @Country varchar(50)= 'Brazil';
WITH ModeData AS (
SELECT country,
a.Mode
FROM df
CROSS APPLY (
SELECT TOP 1 Mode, COUNT(*) AS cnt
FROM (VALUES (val1), (val2), (val3)) AS t(Mode)
GROUP BY Mode
ORDER BY COUNT(*) DESC
) a
where year = @year --and country=@country
)
SELECT
country,
COUNT(CASE WHEN Mode = 1 THEN 1 END) * 1.0 / COUNT(*) AS [Very Dissatisfied],
COUNT(CASE WHEN Mode = 2 THEN 1 END) * 1.0 / COUNT(*) AS [Dissatisfied],
COUNT(CASE WHEN Mode = 3 THEN 1 END) * 1.0 / COUNT(*) AS [Neutral],
COUNT(CASE WHEN Mode = 4 THEN 1 END) * 1.0 / COUNT(*) AS [Satisfied],
COUNT(CASE WHEN Mode = 5 THEN 1 END) * 1.0 / COUNT(*) AS [Very Satisfied],
COUNT(*) AS Count
FROM ModeData
GROUP BY
country
ORDER BY
country;