Làm thế nào để đếm số lần xuất hiện của một giá trị cột một cách hiệu quả trong SQL?


166

Tôi có một bảng sinh viên:

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

Tôi muốn truy vấn tất cả các sinh viên và một cột bổ sung cho biết có bao nhiêu sinh viên cùng tuổi:

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

Cách hiệu quả nhất để làm điều này là gì? Tôi sợ rằng một truy vấn phụ sẽ chậm và tôi tự hỏi liệu có cách nào tốt hơn không . Lanhung?

Câu trả lời:


255

Điều này sẽ làm việc:

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

Nếu bạn cần id, bạn có thể bao gồm ở trên dưới dạng truy vấn phụ như vậy:

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
đối với truy vấn thứ hai, lựa chọn bên ngoài phải nằm trên C.cnt vì không có S.cnt, nếu không bạn sẽ gặp lỗi: Tên cột không hợp lệ 'cnt'
KM.

1
nó đưa ra lỗi cho tôi khi tôi đang sử dụng select case_id, Count (pgm_code) từ nhóm pgm theo pgm_code; nó nói không phải là một nhóm theo biểu hiện
Rishabh Agarwal

26

Nếu bạn đang sử dụng Oracle, thì một tính năng được gọi là phân tích sẽ thực hiện thủ thuật. Nó trông như thế này:

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

Nếu bạn không sử dụng Oracle, thì bạn sẽ cần phải quay lại đếm:

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, Trên SQL Server 2005, truy vấn thứ hai chạy với gần một nửa chi phí thực hiện (sử dụng SET SHOWPLAN_ALL ON ) làm truy vấn đầu tiên. Tôi nghĩ rằng đầu tiên sẽ tốt hơn, nhưng trường cũ tham gia đánh bại nó.
KM.

1
"tham gia trường học cũ đánh bại nó" đơn giản vì TOTAL ROW COUNT được xử lý là khác nhau. Trong truy vấn thứ hai, có nhóm nhúng theo đó có khả năng làm giảm đáng kể số lượng hàng. Hãy thử thêm DISTINCT vào truy vấn đầu tiên: "chọn id DISTINCT, tuổi, đếm (*) trên (phân vùng theo độ tuổi) từ học sinh" - điều đó có thể so sánh được
quetzalcoatl

19

Đây là một giải pháp khác. cái này sử dụng cú pháp rất đơn giản. Ví dụ đầu tiên về giải pháp được chấp nhận không hoạt động trên các phiên bản Microsoft SQL cũ hơn (tức là 2000)

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

1
Nếu bạn nhóm theo độ tuổi, bạn sẽ chỉ nhận được một mục nhập cho tuổi 25 với số lượng là 2 (khi họ thực sự muốn có 2 mục với số lượng 2 và id riêng biệt cho ví dụ đã cho)?
Ian

1
Ian, cảm ơn đã phản hồi. Bạn đã thực hiện yêu cầu của mình đối với MS SQL 2000 DB chưa?
Damian

7

Tôi sẽ làm một cái gì đó như:

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

và nếu dữ liệu trong cột "tuổi" có hồ sơ tương tự (nghĩa là nhiều người 25 tuổi, nhiều người khác là 32 tuổi), điều đó gây ra sự nhầm lẫn trong việc căn chỉnh số đếm đúng cho mỗi học sinh. để tránh điều đó, tôi cũng tham gia các bảng trên ID sinh viê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*
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.