Bagaimana cara menghitung kemunculan nilai kolom secara efisien dalam SQL?

166

Saya punya meja siswa:

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

Saya ingin menanyakan semua siswa, dan kolom tambahan yang menghitung berapa banyak siswa dengan usia yang sama:

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

Apa cara paling efisien untuk melakukan ini? Saya khawatir sub-permintaan akan lambat, dan saya bertanya-tanya apakah ada cara yang lebih baik . Disana?

Assaf Lavie
sumber

Jawaban:

255

Ini seharusnya bekerja:

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

Jika Anda memerlukan id juga Anda bisa memasukkan di atas sebagai sub kueri seperti:

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
sumber
2
untuk kueri kedua, pilih luar harus di C.cnt karena tidak ada S.cnt, jika tidak Anda mendapatkan kesalahan: Nama kolom 'cnt'
KM
1
itu memberikan kesalahan bagi saya ketika saya menggunakan pilih case_id, hitung (pgm_code) dari grup pgm oleh pgm_code; itu mengatakan bukan grup dengan ekspresi
Rishabh Agarwal
26

Jika Anda menggunakan Oracle, maka fitur yang disebut analytics akan berhasil. Ini terlihat seperti ini:

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

Jika Anda tidak menggunakan Oracle, maka Anda harus bergabung kembali ke penghitungan:

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
sumber
2
FYI, Pada SQL Server 2005, kueri kedua berjalan dengan hampir setengah biaya eksekusi (menggunakan SET SHOWPLAN_ALL ON ) sebagai yang pertama. Saya pikir yang pertama akan lebih baik, tetapi sekolah tua bergabung mengalahkannya.
KM.
1
"old school join beat it" hanya karena TOTAL ROW COUNT yang akan diproses berbeda. Di kueri kedua, ada grup tertanam yang berpotensi sangat mengurangi jumlah baris. Coba tambahkan DISTINCT ke kueri pertama: "pilih DISTINCT id, umur, hitung (*) di atas (partisi berdasarkan usia) dari siswa" - yang seharusnya sebanding
quetzalcoatl
19

Ini solusi lain. ini menggunakan sintaks yang sangat sederhana. Contoh pertama dari solusi yang diterima tidak berfungsi pada versi Microsoft SQL yang lebih lama (yaitu 2000)

SELECT age, count(*)
FROM Students 
GROUP by age
ORDER BY age
Damian
sumber
1
Jika Anda mengelompokkan berdasarkan usia, Anda hanya akan mendapatkan satu entri untuk usia 25 dengan hitungan 2 (padahal mereka sebenarnya menginginkan 2 entri dengan hitungan 2 dan pisahkan id untuk contoh yang diberikan)?
Ian
1
Ian, terima kasih atas umpan baliknya. Apakah Anda menjalankan klaim Anda terhadap MS SQL 2000 DB?
Damian
7

Saya akan melakukan sesuatu seperti:

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

dan jika data dalam kolom "usia" memiliki catatan yang sama (yaitu banyak orang berusia 25 tahun, banyak lainnya berusia 32 tahun dan seterusnya), hal itu menyebabkan kebingungan dalam menyelaraskan jumlah yang tepat untuk setiap siswa. untuk menghindarinya, saya bergabung dengan tabel pada ID siswa juga.

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
sumber