Как эффективно посчитать вхождения значения столбца в SQL?

166

У меня есть таблица студентов:

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

Я хочу сделать запрос для всех студентов, и дополнительный столбец, который подсчитывает, сколько студентов одного возраста:

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

Какой самый эффективный способ сделать это? Я боюсь, что подзапрос будет медленным, и мне интересно, есть ли лучший способ . Здесь?

Ассаф Лави
источник

Ответы:

256

Это должно работать:

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

Если вам также нужен идентификатор, вы можете включить вышеперечисленное в качестве подзапроса следующим образом:

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
для второго запроса внешний выбор должен быть на C.cnt, потому что нет S.cnt, в противном случае вы получите ошибку: Неверное имя столбца 'cnt'
KM.
1
это дает мне ошибку, когда я использую select case_id, count (pgm_code) из группы pgm с помощью pgm_code; это говорит не группа выражением
Rishabh Agarwal
26

Если вы используете Oracle, то подойдет функция аналитики. Это выглядит так:

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

Если вы не используете Oracle, вам нужно присоединиться к подсчетам:

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
К сведению, на SQL Server 2005 второй запрос выполняется почти с половиной затрат на выполнение (используя SET SHOWPLAN_ALL ON ) в качестве первого. Я думал, что первое было бы лучше, но присоединение старой школы победило его.
КМ.
1
«присоединиться к старой школе побить это» просто потому, что ОБЩАЯ СЧЕТЧИК СТРОКИ будет обрабатываться иначе. Во втором запросе есть встроенная группировка, которая потенциально значительно уменьшает количество строк. Попробуйте добавить DISTINCT к первому запросу: «выберите DISTINCT id, age, count (*) over (разбиение по возрасту) из студентов» - это должно быть сопоставимо
quetzalcoatl
19

Вот еще одно решение. этот использует очень простой синтаксис. Первый пример принятого решения не работал на старых версиях Microsoft SQL (т.е. 2000)

SELECT age, count(*)
FROM Students 
GROUP by age
ORDER BY age
Damian
источник
1
Однако если вы группируете по возрасту, вы получите только одну запись для 25 лет со счетом 2 (когда они на самом деле хотят 2 записи со счетом 2 и отдельными идентификаторами для данного примера)?
Ян
1
Йен, спасибо за отзыв. Вы выполнили свою претензию к БД MS SQL 2000?
Дамиан
7

Я хотел бы сделать что-то вроде:

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;
quosoo
источник
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
RedFilter
источник
1

и если данные в столбце «возраст» имеют похожие записи (т.е. многим людям 25 лет, многим другим 32 года и т. д.), это приводит к путанице при выравнивании правильного количества для каждого учащегося. Чтобы избежать этого, я присоединился к таблицам по студенческому удостоверению личности.

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*
afii_palang
источник