Giải pháp thích hợp
SELECT *
FROM (
SELECT day::date
FROM generate_series(timestamp '2007-12-01'
, timestamp '2008-12-01'
, interval '1 month') day
) d
LEFT JOIN (
SELECT date_trunc('month', date_col)::date AS day
, count(*) AS some_count
FROM tbl
WHERE date_col >= date '2007-12-01'
AND date_col <= date '2008-12-06'
-- AND ... more conditions
GROUP BY 1
) t USING (day)
ORDER BY day;
-
Sử dụng
LEFT JOIN
, tất nhiên. -
generate_series()
có thể tạo một bảng dấu thời gian một cách nhanh chóng và rất nhanh. -
Nói chung, tổng hợp trước sẽ nhanh hơn bạn tham gia. Gần đây, tôi đã cung cấp một trường hợp thử nghiệm trên sqlfiddle.com trong câu trả lời có liên quan này:
- PostgreSQL - sắp xếp theo một mảng
-
Truyền
timestamp
đếndate
(::date
) cho một định dạng cơ bản. Để sử dụng thêmto_char()
. -
GROUP BY 1
là viết tắt cú pháp để tham chiếu cột đầu ra đầu tiên. Có thể làGROUP BY day
nhưng điều đó có thể xung đột với một cột hiện có cùng tên. HoặcGROUP BY date_trunc('month', date_col)::date
nhưng điều đó quá lâu so với sở thích của tôi. -
Hoạt động với các đối số khoảng thời gian có sẵn cho
date_trunc()
. -
count()
không bao giờ tạo raNULL
(0
không có hàng), nhưngLEFT JOIN
hiện.
Để trả về0
thay vìNULL
trongSELECT
bên ngoài , sử dụngCOALESCE(some_count, 0) AS some_count
. Hướng dẫn sử dụng. -
Để có giải pháp chung chung hơn hoặc khoảng thời gian tùy ý hãy xem xét câu trả lời có liên quan chặt chẽ này:
- Cách tốt nhất để đếm các bản ghi theo khoảng thời gian tùy ý trong Rails + Postgres