I would like to find the percentage of "good", "normal", and "bad" included in the surveys. What kind of SQL should I write?
Contents of surveys table (13 items in total)
id | user_id | answer |
---|---|---|
1 | 251 | Was good |
2 | 113 | Was good |
3 | 46 | Usually |
4 | 414 | Was good |
5 | 456 | Was good |
6 | 18 | Usually |
7 | 173 | Usually |
8 | 441 | Was good |
9 | 419 | It was bad |
10 | 157 | Usually |
11 | 116 | Was good |
12 | 204 | Was good |
13 | 445 | It was bad |
Value you want to calculate
--Good = 53.8% (because there are 7) --Usually = 30.8% (because there are 4 cases) --It was bad = 15.4% (because there are 2 cases)
It can be calculated with such SQL.
SELECT
TO_CHAR(
100.0 * SUM(CASE WHEN answer = 'Was good' THEN 1 ELSE 0 END) / COUNT(*),
'999.9%'
) AS "Was good",
TO_CHAR(
100.0 * SUM(CASE WHEN answer = 'Usually' THEN 1 ELSE 0 END) / COUNT(*),
'999.9%'
) AS "Usually",
TO_CHAR(
100.0 * SUM(CASE WHEN answer = 'It was bad' THEN 1 ELSE 0 END) / COUNT(*),
'999.9%'
) AS "It was bad"
FROM surveys
Output result
Was good | Usually | It was bad | |
---|---|---|---|
1 | 53.8% | 30.8% | 15.4% |
--SUM (CASE WHEN answer ='Good' THEN 1 ELSE 0 END)
counts how many" good "were. (7 here)
--Count the total number of items in the table with COUNT (*)
(13 here)
--You can calculate the percentage by dividing by the above two numbers and multiplying by 100.
--However, since the division between integers is rounded to an integer value, 7 ÷ 13 × 100 = 0. To avoid that, multiply by 100.0 first instead of 100. As a result, the value after the decimal point is also calculated. (100.0 × 7 ÷ 13 = 53.8461538)
--Finally, format the number with the TO_CHAR
function (TO_CHAR (53.8461538, '999.9%')
→53.8%
)
--Calculate the percentage of "normal" and "bad" using the same procedure
You can check the SQL execution result by accessing the following site and clicking the "Run it" button.
https://rextester.com/XINWIX39774
If you implement it with Ruby on Rails, it looks like this.
#Write SQL in SELECT clause
sql = <<~SQL
100.0 * SUM(CASE WHEN answer = 'Was good' THEN 1 ELSE 0 END) / COUNT(*) AS good,
100.0 * SUM(CASE WHEN answer = 'Usually' THEN 1 ELSE 0 END) / COUNT(*) AS fair,
100.0 * SUM(CASE WHEN answer = 'It was bad' THEN 1 ELSE 0 END) / COUNT(*) AS bad
SQL
#Execute SQL to get the value
survey = Survey.select(sql)[0]
survey.good #=> 53.8461538
survey.fair #=> 30.7692308
survey.bad #=> 15.3846154
Supplementary explanation
--If you change the column alias to Japanese, it will not be compatible with the program, so here it is good / fair / bad.
--The value format is View's responsibility, so here we just return the calculated value purely.
--If you set Survey.select (sql) .first
, the ORDER BY clause will be added automatically and an SQL error will occur, so I dared to set it to[0]
.
From the comment section of this article.
SELECT
TO_CHAR(
AVG(CASE WHEN answer = 'Was good' THEN 100 ELSE 0 END),
'999.9%'
) AS "Was good",
TO_CHAR(
AVG(CASE WHEN answer = 'Usually' THEN 100 ELSE 0 END),
'999.9%'
) AS "Usually",
TO_CHAR(
AVG(CASE WHEN answer = 'It was bad' THEN 100 ELSE 0 END),
'999.9%'
) AS "It was bad"
FROM surveys;
(The execution result is the same as the above text)
SELECT
answer,
TO_CHAR(
100.0 * COUNT(*) / (SELECT COUNT(*) FROM surveys),
'999.9%'
) AS "rate"
FROM surveys
GROUP BY answer
ORDER BY rate DESC;
Execution result
answer | rate |
---|---|
Was good | 53.8% |
Usually | 30.8% |
It was bad | 15.4% |
Recommended Posts