2009-10-01 32 views
113

Tengo una tabla de los estudiantes:¿Cómo contar las ocurrencias de un valor de columna de manera eficiente en SQL?

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

Quiero consultar para todos los estudiantes, y una columna adicional que cuenta el número de estudiantes son de la misma edad:

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

¿Cuál es la más eficiente forma de hacer esto? Me temo que una sub-consulta será lenta, y me pregunto si hay una mejor manera de. ¿Esta ahí?

+0

Dado que la sub consulta es estática solo necesita ejecutarla una vez y puede almacenar el resultado en una tabla temporal, como la mayoría de estas respuestas lo han hecho. –

+1

@NickLarsen, una tabla temporal es muy diferente y menos eficiente que las tablas derivadas (también conocidas como vistas en línea) que usan la mayoría de las respuestas aquí. –

Respuesta

166

Esto debería funcionar:

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

Si necesita el id, así que podría incluir lo anterior como una consulta sub 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 
+1

para la segunda consulta, la selección externa debe estar en C.cnt porque no hay S.cnt; de lo contrario, aparece un error: el nombre de la columna no válida 'cnt' –

+0

me da un error cuando uso select case_id, count (pgm_code) del grupo pgm por pgm_code; no dice un grupo por expresión –

3
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 
6

Me gustaría hacer algo como:

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; 
19

Si está utilizando Oracl e, entonces una característica llamada análisis hará el truco. Se ve así:

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

Si no está utilizando Oracle, entonces usted tendrá que volver a unirse a los recuentos:

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

+1, la primera consulta funciona para SQL Server 2005 y también –

+1

FYI, en SQL Server 2005, la segunda consulta se ejecuta con casi la mitad del costo de ejecución (usando _SET SHOWPLAN_ALL ON_) como la primera. Pensé que el primero hubiera sido mejor, pero el antiguo grupo de la escuela lo superó. –

+0

Esto funcionó para mí: la declaración de partición recolectó muy bien los recuentos de valores únicos para mi columna. – theJerm

15

Aquí hay otra solución. este usa una sintaxis muy simple. El primer ejemplo de la solución aceptada no funcionaba en versiones anteriores de Microsoft SQL (es decir, 2000)

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

Solución muy agradable y fácil. – schlingel

+0

Si agrupa por edad, solo obtendría una entrada para los 25 años con un recuento de 2 (cuando en realidad quieren 2 entradas con un recuento de 2 e identificaciones separadas para el ejemplo dado)? – Ian

+0

Ian, gracias por los comentarios. ¿Ejecutaste tu reclamo contra un MS SQL 2000 DB? – Damian

0

y si los datos en la columna "edad" tiene registros similares (es decir, muchas personas están 25 años de edad, muchos otros son 32 y así sucesivamente), causa confusión al alinear el conteo correcto para cada estudiante. para evitarlo, me uní a las tablas en la identificación del estudiante también.

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* 
Cuestiones relacionadas