2012-03-13 8 views
8

Given:SQL truy vấn phân phối tần số để đếm dãy với nhóm-by và bao gồm 0 đếm

table 'thing': 

age 
--- 
3.4 
3.4 
10.1 
40 
45 
49 

Tôi muốn đếm số thứ cho mỗi khoảng 10 năm, ví dụ:

age_range | count 
----------+------- 
     0 |  2 
     10|  1 
     20|  0 
     30|  0 
     40|  3 

truy vấn này đến gần:

SELECT FLOOR(age/10) as age_range, COUNT(*) 
FROM thing 
GROUP BY FLOOR(age/10) ORDER BY FLOOR(age/10); 

Output:

age_range | count 
-----------+------- 
     0 |  1 
     1 |  2 
     4 |  3 

Tuy nhiên, nó không hiển thị cho tôi phạm vi có 0 lần đếm. Làm thế nào tôi có thể sửa đổi truy vấn để nó cũng hiển thị các phạm vi ở giữa với 0 đếm?

Tôi đã tìm thấy các câu hỏi xếp chồng tương tự cho các phạm vi đếm, một số cho 0 đếm, nhưng chúng liên quan đến việc chỉ định từng phạm vi (mã hóa cứng phạm vi vào truy vấn hoặc đặt phạm vi trong bảng). Tôi muốn sử dụng truy vấn chung như trên ở đây tôi không phải chỉ định rõ từng phạm vi (ví dụ: 0-10, 10-20, 20-30, ...). Tôi đang sử dụng PostgreSQL 9.1.3.

Có cách nào để sửa đổi truy vấn đơn giản ở trên để bao gồm 0 lần đếm không?

tương tự:
Oracle: how to "group by" over a range?
Get frequency distribution of a decimal range in MySQL

Trả lời

10

generate_series để giải cứu:

select 10 * s.d, count(t.age) 
from generate_series(0, 10) s(d) 
left outer join thing t on s.d = floor(t.age/10) 
group by s.d 
order by s.d 

Tìm ra các giới hạn trên cho generate_series nên tầm thường với một truy vấn riêng biệt, tôi chỉ sử dụng 10 như là một placeholder .

này:

generate_series(0, 10) s(d) 

về cơ bản tạo ra một bảng nội tuyến gọi s với một cột duy nhất d chứa các giá trị từ 0 đến 10 (bao gồm).

Bạn có thể bao gồm hai truy vấn (một để tìm ra phạm vi, một để tính số lượng) vào một hàm nếu cần.

+0

Đó là tốt đẹp. Chức năng tốt để biết. – Glenn

+0

Câu trả lời thanh lịch, @mu_is_too_short! Tôi đã thử và nó đã hoạt động. Chỉ cần những gì tôi đang tìm kiếm. Cảm ơn! –

+0

@Glenn: Yeah, 'generate_series' rất hữu ích, nó cũng có thể hoạt động với dấu thời gian để tạm biệt các bảng lịch. –

1

Bạn cần một số cách để phát minh ra bảng độ tuổi. Số hàng thường hoạt động tốt. Làm một sản phẩm Descartes với một bảng lớn để có được rất nhiều con số.

WITH RANGES AS (
SELECT (rownum - 1) * 10 AS age_range 
    FROM (SELECT row_number() OVER() as rownum 
      FROM pg_tables 
     ) n 
     ,(SELECT ceil(max(age)/10) range_end 
      FROM thing 
     ) m 
    WHERE n. rownum <= range_end 
) 
SELECT r.age_range, COUNT(t.age) AS count 
    FROM ranges r 
    LEFT JOIN thing t ON r.age_range = FLOOR(t.age/10) * 10 
    GROUP BY r.age_range 
    ORDER BY r.age_range; 

EDIT: mu là quá ngắn có một câu trả lời nhiều thanh lịch hơn, nhưng nếu bạn không có một chức năng generate_series trên db, ... :)