Come calcolare la percentuale con un’istruzione SQL

Ho una tabella di SQL Server che contiene gli utenti e i loro voti. Per semplicità, diciamo solo che ci sono 2 colonne: name e grade . Quindi una riga tipica sarebbe Nome: “John Doe”, Grade: “A”.

Sto cercando una dichiarazione SQL che trovi le percentuali di tutte le possibili risposte. (A, B, C, ecc …) Inoltre, c’è un modo per farlo senza definire tutte le possibili risposte (campo di testo aperto – gli utenti possono inserire ‘pass / fail’, ‘none’, ecc …)

L’output finale che sto cercando è A: 5%, B: 15%, C: 40%, ecc …

Ho provato quanto segue e questo funziona. La risposta di gordyii era vicina ma aveva la moltiplicazione di 100 nel posto sbagliato e aveva qualche parentesi mancante.

 Select Grade, (Count(Grade)* 100 / (Select Count(*) From MyTable)) as Score From MyTable Group By Grade 
  1. Il più efficiente (usando over ()).

     select Grade, count(*) * 100.0 / sum(count(*)) over() from MyTable group by Grade 
  2. Universale (qualsiasi versione SQL).

     select Rate, count(*) * 100.0 / (select count(*) from MyTable) from MyTable group by Rate; 
  3. Con CTE, il meno efficiente.

     with t(Rate, RateCount) as ( select Rate, count(*) from MyTable group by Rate ) select Rate, RateCount * 100.0/(select sum(RateCount) from t) from t; 

Invece di utilizzare un CTE separato per ottenere il totale, è ansible utilizzare una funzione di finestra senza la clausola “partition by”.

Se stai usando:

 count(*) 

per ottenere il conteggio per un gruppo, puoi utilizzare:

 sum(count(*)) over () 

per ottenere il conteggio totale.

Per esempio:

 select Grade, 100. * count(*) / sum(count(*)) over () from table group by Grade; 

Tende ad essere più veloce nella mia esperienza, ma penso che in alcuni casi potrebbe utilizzare una tabella temporanea (ho visto “Worktable” quando è in esecuzione con “set statistiche io on”).

EDIT: Non sono sicuro se la mia query di esempio è ciò che stai cercando, stavo solo illustrando come funzionano le funzioni di windowing.

Devi calcolare il totale dei voti Se è SQL 2005 puoi usare 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 

È necessario raggruppare nel campo del grado. Questa query dovrebbe darti quello che stai cercando in quasi tutti i database.

  Select Grade, CountofGrade / sum(CountofGrade) *100 from ( Select Grade, Count(*) as CountofGrade From Grades Group By Grade) as sub Group by Grade 

Devi specificare il sistema che stai utilizzando.

Semplicemente uso questo quando ho bisogno di calcolare una percentuale ..

 ROUND(CAST((Numerator * 100.0 / Denominator) AS FLOAT), 2) AS Percentage 

Notare che 100.0 restituisce decimali, mentre 100 su proprio arrotonderà il risultato al numero intero più vicino, anche con la funzione ROUND ()!

Questa è, credo, una soluzione generale, sebbene l’ho provata utilizzando IBM Informix Dynamic Server 11.50.FC3. La seguente domanda:

 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; 

dà il seguente risultato sui dati del test mostrati sotto la regola orizzontale. La funzione ROUND può essere specifica per DBMS, ma il resto (probabilmente) non lo è. (Notare che ho modificato da 100 a 100.0 per garantire che il calcolo si verifichi utilizzando non intero – DECIMALE, NUMERICO – aritmetico, vedere i commenti e grazie a 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'); 

Il seguente dovrebbe funzionare

 ID - Key Grade - A,B,C,D... 

EDIT: spostato il * 100 e aggiunto 1.0 per assicurarsi che non faccia divisione integer

 Select Grade, Count(ID) * 100.0 / ((Select Count(ID) From MyTable) * 1.0) From MyTable Group By Grade 

In qualsiasi versione di SQL Server è ansible utilizzare una variabile per il totale di tutti i gradi come questo:

 declare @countOfAll decimal(18, 4) select @countOfAll = COUNT(*) from Grades select Grade, COUNT(*) / @countOfAll * 100 from Grades group by Grade 

Puoi utilizzare una sottoselezione nella tua query (non testata e non sicura quale sia più veloce):

 SELECT Grade, COUNT(*) / TotalRows FROM (SELECT Grade, COUNT(*) As TotalRows FROM myTable) Grades GROUP BY Grade, TotalRows 

O

 SELECT Grade, SUM(PartialCount) FROM (SELECT Grade, 1/COUNT(*) AS PartialCount FROM myTable) Grades GROUP BY Grade 

O

 SELECT Grade, GradeCount / SUM(GradeCount) FROM (SELECT Grade, COUNT(*) As GradeCount FROM myTable GROUP BY Grade) Grades 

È anche ansible utilizzare una stored procedure (scuse per la syntax di 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 
 SELECT Grade, GradeCount / SUM(GradeCount) FROM (SELECT Grade, COUNT(*) As GradeCount FROM myTable GROUP BY Grade) Grades