J'ai une table SQL Server qui contient les utilisateurs et leurs notes. Par souci de simplicité, disons simplement qu'il y a 2 colonnes - name
& grade
. Ainsi, une ligne typique serait Nom: "John Doe", Grade: "A".
Je cherche une instruction SQL qui trouvera les pourcentages de toutes les réponses possibles. (A, B, C, etc ...) En outre, existe-t-il un moyen de le faire sans définir toutes les réponses possibles (champ de texte ouvert - les utilisateurs peuvent entrer "réussite/échec", "aucune", etc.)
Le résultat final recherché est A: 5%, B: 15%, C: 40%, etc ...
J'ai testé les éléments suivants et cela fonctionne. La réponse de gordyii était proche, mais la multiplication de 100 était au mauvais endroit et il manquait une parenthèse.
Select Grade, (Count(Grade)* 100 / (Select Count(*) From MyTable)) as Score
From MyTable
Group By Grade
Le plus efficace (utiliser over ()).
select Grade, count(*) * 100.0 / sum(count(*)) over()
from MyTable
group by Grade
Universel (toute version SQL).
select Grade, count(*) * 100.0 / (select count(*) from MyTable)
from MyTable
group by Grade;
Avec CTE, le moins efficace.
with t(Grade, GradeCount)
as
(
select Grade, count(*)
from MyTable
group by Grade
)
select Grade, GradeCount * 100.0/(select sum(GradeCount) from t)
from t;
Au lieu d'utiliser un CTE distinct pour obtenir le total, vous pouvez utiliser une fonction de fenêtre sans la clause "partition by".
Si vous utilisez:
count(*)
pour obtenir le compte d'un groupe, vous pouvez utiliser:
sum(count(*)) over ()
pour obtenir le compte total.
Par exemple:
select Grade, 100. * count(*) / sum(count(*)) over ()
from table
group by Grade;
Mon expérience a tendance à être plus rapide, mais je pense que dans certains cas, une table temporaire peut être utilisée en interne (j'ai vu "Worktable" lors de l'exécution avec "set statistics io on").
EDIT: Je ne suis pas sûr que mon exemple de requête corresponde à ce que vous recherchez, je viens d’illustrer le fonctionnement des fonctions de fenêtrage.
Vous devez calculer le total des notes S'il s'agit de SQL 2005, vous pouvez utiliser CTE
WITH Tot(Total) (
SELECT COUNT(*) FROM table
)
SELECT Grade, COUNT(*) / Total * 100
--, CONVERT(VARCHAR, COUNT(*) / Total * 100) + '%' -- With percentage sign
--, CONVERT(VARCHAR, ROUND(COUNT(*) / Total * 100, -2)) + '%' -- With Round
FROM table
GROUP BY Grade
Vous devez grouper sur le champ de qualité. Cette requête devrait vous donner ce que vous cherchez dans à peu près n'importe quelle base de données.
Select Grade, CountofGrade / sum(CountofGrade) *100
from
(
Select Grade, Count(*) as CountofGrade
From Grades
Group By Grade) as sub
Group by Grade
Vous devez spécifier le système que vous utilisez.
J'utilise tout simplement cela chaque fois que j'ai besoin de calculer un pourcentage ..
ROUND(CAST((Numerator * 100.0 / Denominator) AS FLOAT), 2) AS Percentage
Notez que 100.0 retourne les décimales, alors que 100 seul arrondira le résultat au nombre entier le plus proche, même avec la fonction ROUND ()!
Ce qui suit devrait fonctionner
ID - Key
Grade - A,B,C,D...
EDIT: Déplacement du * 100
et ajout du 1.0
pour s’assurer qu’il ne fait pas la division entière
Select
Grade, Count(ID) * 100.0 / ((Select Count(ID) From MyTable) * 1.0)
From MyTable
Group By Grade
Je pense que c'est une solution générale, même si je l'ai testée avec IBM Informix Dynamic Server 11.50.FC3. La requête suivante:
SELECT grade,
ROUND(100.0 * grade_sum / (SELECT COUNT(*) FROM grades), 2) AS pct_of_grades
FROM (SELECT grade, COUNT(*) AS grade_sum
FROM grades
GROUP BY grade
)
ORDER BY grade;
donne le résultat suivant sur les données de test affichées sous la règle horizontale. La fonction ROUND
peut être spécifique au SGBD, mais le reste (probablement) ne l’est pas. (Notez que j'ai changé 100 à 100.0 pour m'assurer que le calcul s'effectue avec une arithmétique non-entière - DECIMAL, NUMERIC - voir les commentaires et grâce à Thunder.)
grade pct_of_grades
CHAR(1) DECIMAL(32,2)
A 32.26
B 16.13
C 12.90
D 12.90
E 9.68
F 16.13
CREATE TABLE grades
(
id VARCHAR(10) NOT NULL,
grade CHAR(1) NOT NULL CHECK (grade MATCHES '[ABCDEF]')
);
INSERT INTO grades VALUES('1001', 'A');
INSERT INTO grades VALUES('1002', 'B');
INSERT INTO grades VALUES('1003', 'F');
INSERT INTO grades VALUES('1004', 'C');
INSERT INTO grades VALUES('1005', 'D');
INSERT INTO grades VALUES('1006', 'A');
INSERT INTO grades VALUES('1007', 'F');
INSERT INTO grades VALUES('1008', 'C');
INSERT INTO grades VALUES('1009', 'A');
INSERT INTO grades VALUES('1010', 'E');
INSERT INTO grades VALUES('1001', 'A');
INSERT INTO grades VALUES('1012', 'F');
INSERT INTO grades VALUES('1013', 'D');
INSERT INTO grades VALUES('1014', 'B');
INSERT INTO grades VALUES('1015', 'E');
INSERT INTO grades VALUES('1016', 'A');
INSERT INTO grades VALUES('1017', 'F');
INSERT INTO grades VALUES('1018', 'B');
INSERT INTO grades VALUES('1019', 'C');
INSERT INTO grades VALUES('1020', 'A');
INSERT INTO grades VALUES('1021', 'A');
INSERT INTO grades VALUES('1022', 'E');
INSERT INTO grades VALUES('1023', 'D');
INSERT INTO grades VALUES('1024', 'B');
INSERT INTO grades VALUES('1025', 'A');
INSERT INTO grades VALUES('1026', 'A');
INSERT INTO grades VALUES('1027', 'D');
INSERT INTO grades VALUES('1028', 'B');
INSERT INTO grades VALUES('1029', 'A');
INSERT INTO grades VALUES('1030', 'C');
INSERT INTO grades VALUES('1031', 'F');
SELECT Grade, GradeCount / SUM(GradeCount)
FROM (SELECT Grade, COUNT(*) As GradeCount
FROM myTable
GROUP BY Grade) Grades
Dans toute version de serveur SQL, vous pouvez utiliser une variable pour le total de toutes les notes, comme ceci:
declare @countOfAll decimal(18, 4)
select @countOfAll = COUNT(*) from Grades
select
Grade, COUNT(*) / @countOfAll * 100
from Grades
group by Grade
Vous pouvez utiliser une sous-sélection dans votre requête from (non testée et ne sachant pas laquelle est la plus rapide):
SELECT Grade, COUNT(*) / TotalRows
FROM (SELECT Grade, COUNT(*) As TotalRows
FROM myTable) Grades
GROUP BY Grade, TotalRows
Ou
SELECT Grade, SUM(PartialCount)
FROM (SELECT Grade, 1/COUNT(*) AS PartialCount
FROM myTable) Grades
GROUP BY Grade
Ou
SELECT Grade, GradeCount / SUM(GradeCount)
FROM (SELECT Grade, COUNT(*) As GradeCount
FROM myTable
GROUP BY Grade) Grades
Vous pouvez également utiliser une procédure stockée (excuses pour la syntaxe Firebird):
SELECT COUNT(*)
FROM myTable
INTO :TotalCount;
FOR SELECT Grade, COUNT(*)
FROM myTable
GROUP BY Grade
INTO :Grade, :GradeCount
DO
BEGIN
Percent = :GradeCount / :TotalCount;
SUSPEND;
END