Bir sütun değerinin oluşumlarını SQL'de verimli bir şekilde nasıl sayabilirim?


166

Bir öğrenci masam var:

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

Tüm öğrenciler ve aynı yaştaki kaç öğrenciyi sayan ek bir sütun sorgulamak istiyorum:

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

Bunu yapmanın en etkili yolu nedir? Bir alt sorgunun yavaş olacağından korkuyorum ve daha iyi bir yol olup olmadığını merak ediyorum . Var mı?

Yanıtlar:


256

Bu çalışmalı:

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

Kimliğe de ihtiyacınız varsa, yukarıdaki gibi bir alt sorgu olarak aşağıdakileri ekleyebilirsiniz:

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
ikinci sorgu için, dış seçim C.cnt üzerinde olmalıdır çünkü S.cnt yoktur, aksi takdirde bir hata alırsınız: Geçersiz sütun adı 'cnt'
KM.

1
pgm_code tarafından pgm grubundan select case_id, count (pgm_code) kullanırken benim için hata veriyor; ifade ile bir grup değil diyor
Rishabh Agarwal

26

Oracle kullanıyorsanız, analitik adı verilen bir özellik işe yarayacaktır. Şöyle görünüyor:

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

Oracle kullanmıyorsanız, sayılara tekrar katılmanız gerekir:

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
FYI, SQL Server 2005'te, ikinci sorgu ilk olarak yürütme maliyetinin neredeyse yarısı ( SET SHOWPLAN_ALL ON kullanarak ) ile çalışır . İlkinin daha iyi olacağını düşünmüştüm, ama eski okul katılımı onu yendi.
KM.

1
işlenecek TOPLAM SIRA SAYISI farklı olduğu için "eski okul birleştirme yendi". İkinci sorguda, satır sayısını potansiyel olarak büyük ölçüde azaltan gömülü bir gruplama vardır. İlk sorguya DISTINCT eklemeyi deneyin: "öğrencilerden DISTINCT id, age, count (*) over (yaşa göre bölünme) seçin" - bu karşılaştırılabilir olmalıdır
quetzalcoatl

19

İşte başka bir çözüm. bu çok basit bir sözdizimi kullanır. Kabul edilen çözümün ilk örneği Microsoft SQL'in eski sürümlerinde çalışmadı (örn. 2000)

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

1
Yine de yaşa göre gruplandırırsanız, 25 yaş için yalnızca 2 sayı içeren bir giriş alırsınız (verilen örnek için 2 sayı ve ayrı kimliklere sahip 2 giriş istediklerinde)?
Ian

1
Ian, geri bildiriminiz için teşekkürler. Talebinizi bir MS SQL 2000 DB'ye karşı yürüttünüz mü?
Damian

7

Gibi bir şey yapardı:

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

ve "yaş" sütunundaki veriler benzer kayıtlara sahipse (yani birçok kişi 25 yaşında, diğerleri 32 yaşında vb.), her öğrenciye doğru sayımın hizalanmasında karışıklığa neden olur. bundan kaçınmak için öğrenci kimliği ile ilgili tablolara da katıldım.

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*
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.