Trường hợp thử nghiệm:
CREATE TABLE tbl (date date, email text);
INSERT INTO tbl VALUES
('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-03', '[email protected]')
, ('2012-01-04', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]`')
;
Truy vấn - chỉ trả về những ngày có mục nhập trong tbl
:
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN t.date - 2 AND t.date -- period of 3 days
) AS dist_emails
FROM tbl t
WHERE date BETWEEN '2012-01-01' AND '2012-01-06'
GROUP BY 1
ORDER BY 1;
Hoặc - trở lại tất cả các ngày trong phạm vi được chỉ định, ngay cả khi không có hàng nào trong ngày:
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN g.date - 2 AND g.date
) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date);
db <> fiddle here
Kết quả:
day | dist_emails
-----------+------------
2012-01-01 | 3
2012-01-02 | 3
2012-01-03 | 3
2012-01-04 | 3
2012-01-05 | 1
2012-01-06 | 2
Điều này nghe có vẻ giống như một công việc cho các chức năng cửa sổ lúc đầu, nhưng tôi không tìm ra cách xác định khung cửa sổ phù hợp. Ngoài ra, theo tài liệu:
Các hàm cửa sổ tổng hợp, không giống như các hàm tổng hợp bình thường, không cho phép
DISTINCT
hoặcORDER BY
được sử dụng trong danh sách đối số hàm.
Vì vậy, tôi đã giải quyết nó bằng các truy vấn con tương quan. Tôi đoán đó là cách thông minh nhất.
BTW, "từ ngày đã nói đến 3 ngày trước" sẽ là khoảng thời gian 4 ngày. Định nghĩa của bạn mâu thuẫn ở đó.
Ngắn hơn một chút, nhưng chậm hơn trong vài ngày:
SELECT g.date, count(DISTINCT email) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date)
LEFT JOIN tbl t ON t.date BETWEEN g.date - 2 AND g.date
GROUP BY 1
ORDER BY 1;
Có liên quan:
- Tạo chuỗi thời gian giữa hai ngày trong PostgreSQL
- Số lần cuộn của các hàng trong khoảng thời gian hoạt động