Come contare le occorrenze di un valore di colonna in modo efficiente in SQL?


166

Ho una tabella di studenti:

id | age
--------
0  | 25
1  | 25
2  | 23

Voglio fare una query per tutti gli studenti e una colonna aggiuntiva che conta quanti studenti hanno la stessa età:

id | age | count
----------------
0  | 25  | 2
1  | 25  | 2
2  | 23  | 1

Qual è il modo più efficiente per farlo? Temo che una sottointerrogazione sarà lenta e mi chiedo se esiste un modo migliore . È lì?

Risposte:


255

Questo dovrebbe funzionare:

SELECT age, count(age) 
  FROM Students 
 GROUP by age

Se hai bisogno anche dell'id, puoi includere quanto sopra come una sottoquery in questo modo:

SELECT S.id, S.age, C.cnt
  FROM Students  S
       INNER JOIN (SELECT age, count(age) as cnt
                     FROM Students 
                    GROUP BY age) C ON S.age = C.age

2
per la seconda query, la selezione esterna dovrebbe essere su C.cnt perché non è presente S.cnt, altrimenti verrà visualizzato un errore: Nome colonna non valido 'cnt'
KM.

1
sta dando errore per me quando sto usando select case_id, count (pgm_code) dal gruppo pgm di pgm_code; non dice un gruppo per espressione
Rishabh Agarwal

26

Se stai usando Oracle, allora una funzione chiamata analytics farà il trucco. Sembra così:

select id, age, count(*) over (partition by age) from students;

Se non stai utilizzando Oracle, dovrai ricollegarti ai conteggi:

select a.id, a.age, b.age_count
  from students a
  join (select age, count(*) as age_count
          from students
         group by age) b
    on a.age = b.age

2
Cordiali saluti, Su SQL Server 2005, la seconda query viene eseguita con quasi la metà del costo di esecuzione (utilizzando SET SHOWPLAN_ALL ON ) come prima. Pensavo che il primo sarebbe stato migliore, ma l'adesione alla vecchia scuola l'ha battuto.
KM.

1
"old school join beat it" semplicemente perché il TOTAL ROW COUNT da elaborare è diverso. Nella seconda query, c'è un raggruppamento incorporato che potenzialmente riduce notevolmente il numero di righe. Prova ad aggiungere DISTINCT alla prima query: "seleziona ID DISTINCT, età, conta (*) sopra (partizione per età) dagli studenti" - che dovrebbe essere comparabile
quetzalcoatl

19

Ecco un'altra soluzione. questo usa una sintassi molto semplice. Il primo esempio della soluzione accettata non funzionava con le versioni precedenti di Microsoft SQL (ovvero 2000)

SELECT age, count(*)
FROM Students 
GROUP by age
ORDER BY age

1
Se raggruppate per età, otterreste solo una voce per 25 anni con un conteggio di 2 (quando in realtà vogliono 2 voci con un conteggio di 2 e ID separati per l'esempio fornito)?
Ian

1
Ian, grazie per il feedback. Hai eseguito il tuo reclamo contro un database MS SQL 2000?
Damian,

7

Vorrei fare qualcosa del tipo:

select
 A.id, A.age, B.count 
from 
 students A, 
 (select age, count(*) as count from students group by age) B
where A.age=B.age;

4
select s.id, s.age, c.count
from students s
inner join (
    select age, count(*) as count
    from students
    group by age
) c on s.age = c.age
order by id

1

e se i dati nella colonna "età" hanno record simili (vale a dire che molte persone hanno 25 anni, molte altre ne hanno 32 e così via), crea confusione nell'allineare il conteggio corretto a ogni studente. per evitarlo, mi sono unito anche ai tavoli sull'ID studente.

SELECT S.id, S.age, C.cnt
FROM Students S 
INNER JOIN (SELECT id, age, count(age) as cnt  FROM Students GROUP BY student,age) 
C ON S.age = C.age *AND S.id = C.id*
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.