Wie kann das Auftreten eines Spaltenwerts in SQL effizient gezählt werden?

166

Ich habe einen Schülertisch:

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

Ich möchte alle Schüler abfragen und eine zusätzliche Spalte, in der angegeben wird, wie viele Schüler im gleichen Alter sind:

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

Was ist der effizienteste Weg, dies zu tun? Ich befürchte, dass eine Unterabfrage langsam sein wird, und ich frage mich, ob es einen besseren Weg gibt . Gibt es?

Assaf Lavie
quelle

Antworten:

255

Das sollte funktionieren:

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

Wenn Sie auch die ID benötigen, können Sie die oben genannten als Unterabfrage wie folgt einfügen:

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
Mike Dinescu
quelle
2
Bei der zweiten Abfrage sollte sich die äußere Auswahl auf C.cnt befinden, da kein S.cnt vorhanden ist. Andernfalls wird eine Fehlermeldung angezeigt: Ungültiger Spaltenname 'cnt'
KM.
1
Es gibt einen Fehler für mich, wenn ich select case_id verwende, count (pgm_code) von pgm group by pgm_code; es sagt keine Gruppe durch Ausdruck
Rishabh Agarwal
26

Wenn Sie Oracle verwenden, reicht eine Funktion namens Analytics aus. Es sieht aus wie das:

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

Wenn Sie Oracle nicht verwenden, müssen Sie sich wieder den Zählungen anschließen:

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
Jeremy Bourque
quelle
2
Zu Ihrer Information : Unter SQL Server 2005 wird die zweite Abfrage mit fast der Hälfte der Ausführungskosten (unter Verwendung von SET SHOWPLAN_ALL ON ) als erste ausgeführt. Ich dachte, das erste wäre besser gewesen, aber die alte Schule hat es geschafft.
KM.
1
"old school join beat it", einfach weil der zu verarbeitende TOTAL ROW COUNT anders ist. In der zweiten Abfrage gibt es eine eingebettete Gruppierung, die möglicherweise die Anzahl der Zeilen erheblich reduziert. Versuchen Sie, DISTINCT zur ersten Abfrage hinzuzufügen: "Wählen Sie DISTINCT-ID, Alter, Anzahl (*) über (Partition nach Alter) von Schülern" - das sollte vergleichbar sein
quetzalcoatl
19

Hier ist eine andere Lösung. Dieser verwendet eine sehr einfache Syntax. Das erste Beispiel der akzeptierten Lösung funktionierte nicht mit älteren Versionen von Microsoft SQL (dh 2000).

SELECT age, count(*)
FROM Students 
GROUP by age
ORDER BY age
Damian
quelle
1
Wenn Sie jedoch nach Alter gruppieren, erhalten Sie nur einen Eintrag für 25 Jahre mit einer Anzahl von 2 (wenn sie tatsächlich 2 Einträge mit einer Anzahl von 2 und separaten IDs für das angegebene Beispiel wünschen)?
Ian
1
Ian, danke für das Feedback. Haben Sie Ihren Anspruch gegen eine MS SQL 2000-Datenbank geltend gemacht?
Damian
7

Ich würde so etwas machen wie:

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
quelle
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
quelle
1

und wenn die Daten in der Spalte "Alter" ähnliche Aufzeichnungen enthalten (dh viele Personen sind 25 Jahre alt, viele andere sind 32 Jahre alt usw.), führt dies zu Verwirrung bei der Ausrichtung der richtigen Anzahl auf jeden Schüler. Um dies zu vermeiden, habe ich mich auch an die Tabellen zum Studentenausweis gesetzt.

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
quelle